When building scalable Android or backend applications with Kotlin, choosing the right abstraction is critical. One of the most common design questions Kotlin developers ask is:
What is the difference between a sealed class and a sealed interface in Kotlin, and when should each be used?
This guide provides a complete of sealed class vs sealed interface in Kotlin, including real-world use cases, best practices, and expert design guidance.
What Is a Sealed Class in Kotlin?
A sealed class in Kotlin is a restricted class hierarchy where all subclasses are known at compile time. It allows you to model finite states or results with strong compiler guarantees.
Key Features of Sealed Classes
- Supports constructors
- Can hold state and properties
- Allows shared logic and behavior
- Enables exhaustive
whenexpressions - Supports single inheritance only
Example: Kotlin Sealed Class
sealed class ApiResult {
data class Success(val data: String) : ApiResult()
data class Error(val message: String) : ApiResult()
object Loading : ApiResult()
}
When to Use a Sealed Class
Use a sealed class when:
- You need to model application state
- The base type owns data or logic
- You are building state machines
- You want strict control over object creation
Common use cases
- UI state handling
- Network result wrappers
- Domain state models
- Workflow steps
What Is a Sealed Interface in Kotlin?
A sealed interface in Kotlin defines a closed set of implementations without owning state. It is ideal for modeling events, roles, or contracts.
Introduced to improve flexibility, sealed interfaces are now widely used in Clean Architecture, MVI, and Jetpack Compose.
Key Features of Sealed Interfaces
- Cannot hold state
- No constructors
- Supports multiple inheritance
- Can have default methods
- Enables exhaustive
whenchecks
Example: Kotlin Sealed Interface
sealed interface UiEvent {
data class Click(val id: String) : UiEvent
object Refresh : UiEvent
}
When to Use a Sealed Interface
Use a sealed interface when:
- You are modeling events or intents
- Multiple inheritance is required
- You want flexible, extensible APIs
- The base type should not own data
Common use cases
- UI events
- Domain events
- Marker interfaces
- Public SDK APIs
Sealed Class vs Sealed Interface in Kotlin: Key Differences
| Feature | Sealed Class | Sealed Interface |
|---|---|---|
| Holds state | Yes | No |
| Constructors | Yes | No |
| Inheritance | Single | Multiple |
| Best for | State & logic | Events & roles |
| API flexibility | Lower | Higher |
| Clean Architecture friendly | Moderate | High |
Exhaustive when Expression in Kotlin (Major Benefit)
Both sealed classes and sealed interfaces allow exhaustive when expressions, eliminating the need for else.
when (result) {
is ApiResult.Success -> showData(result.data)
is ApiResult.Error -> showError(result.message)
ApiResult.Loading -> showLoading()
}
This improves:
- Compile-time safety
- Readability
- Refactor confidence
Best Practice: Which One Should You Choose?
Use Sealed Class If:
- The base type represents a concrete concept
- You need shared state or logic
- You are modeling application state
Use Sealed Interface If:
- The base type represents a capability or event
- You want maximum extensibility
- You are designing public or evolving APIs
Expert Rule of Thumb
Prefer sealed interfaces by default.
Upgrade to sealed classes only when state or behavior is required.
Common Mistake Kotlin Developers Make
Using sealed classes without state:
sealed class Event
Better approach:
sealed interface Event
This reduces coupling and improves long-term maintainability.
Why This Matters for Android & Backend Development
In large Kotlin codebases:
- Sealed interfaces improve modularity
- They scale better in Clean Architecture
- They reduce fragile inheritance chains
- They future-proof your domain layer
Sealed classes remain essential—but only when used intentionally.
Final Thoughts: Sealed Class vs Sealed Interface in Kotlin
Understanding the difference between sealed class and sealed interface in Kotlin is not just academic—it directly impacts code quality, scalability, and maintainability.
Quick Summary
- Sealed class → stateful, behavior-rich hierarchies
- Sealed interface → flexible, role-based contracts
- Both → compile-time safety and exhaustive
when
Choosing the right one is a hallmark of senior-level Kotlin development.

