sealed class and sealed interface in Kotlin are mechanisms for bounded type hierarchies where all possible subclasses are known at compile time. Unlike regular abstract classes, a sealed class guarantees exhaustive handling of all variants in a when-expression. According to the JetBrains Kotlin Language Guide (2026), sealed types are the foundation for modeling states, UI screens, and result types in Kotlin projects.
Key Takeaways
sealed class is an abstract class with a restriction: all its direct subclasses must be declared in the same file as the sealed class itself. This restriction makes the hierarchy closed (sealed) — no code outside the file can add a new subclass.
sealed interface, added in Kotlin 1.5, provides the same guarantee but with the flexibility of an interface: a sealed interface can be implemented by multiple classes, objects, or other interfaces in one file. Unlike a sealed class, a sealed interface has no single inheritance restriction — a class can implement multiple sealed interfaces at once.
According to the Kotlin Evolution and Roadmap (2026), sealed interface was added by community request for more flexible modeling. The main motivation is the ability to combine independent type hierarchies without multiple class inheritance.
Declaring a sealed class starts with the sealed modifier before class. Subclasses are declared in the same file.
sealed class NetworkResult {
data class Success(val data: String) : NetworkResult()
data class Error(val message: String) : NetworkResult()
object Loading : NetworkResult()
}
Each subclass of a sealed class can have its own properties and methods. Loading is a singleton (object), Success and Error are data classes with parameters. The compiler knows all three variants and checks their completeness when used in when.
sealed classes can be nested, creating multi-level hierarchies for complex data models without losing type safety.
sealed class UiState {
object Idle : UiState()
object Loading : UiState()
data class Content(val items: List<Item>) : UiState()
data class Error(val exception: Throwable) : UiState()
}
sealed interface is declared similarly to a sealed class but allows implementing multiple sealed interfaces in one class.
sealed interface Action
sealed interface Loggable
data class Navigate(val route: String) : Action, Loggable
data class ShowToast(val text: String) : Action
object GoBack : Action, Loggable
The Navigate class implements two sealed interfaces at once — Action and Loggable. This is impossible with a sealed class due to single inheritance restriction. Sealed interface provides the flexibility to combine independent hierarchies.
sealed interface is preferable when the hierarchy does not require shared state or a constructor. According to the JetBrains Kotlin Guidelines (2026), sealed interface should be used by default for all new hierarchies where a common constructor is not needed, making the code more flexible for future extensions.
The main advantage of sealed types is exhaustive handling in when-expressions. The compiler checks that all possible subclasses are covered.
fun handleResult(result: NetworkResult): String = when (result) {
is NetworkResult.Success -> "Data: ${result.data}"
is NetworkResult.Error -> "Error: ${result.message}"
is NetworkResult.Loading -> "Loading..."
// else is not required — compiler knows all variants are covered
}
If a developer adds a new subclass to a sealed hierarchy but forgets to handle it in when — the compiler will raise an error. This is safety at the type level, unavailable with open hierarchies using else branches.
According to Google Android Developers (2026), sealed classes are the recommended way to model UI state in Jetpack Compose. Exhaustive when checking prevents states where a developer has not handled all possible display variants of a screen.
enum class and sealed class are often confused, but they have different purposes and capabilities.
| Feature | sealed class | enum class |
|---|---|---|
| Instances | Multiple (data class), single (object) | Exactly one per constant |
| Properties | Different for each subclass | Same for all constants |
| Inheritance | Yes (from sealed class) | No (implicit final) |
| Constructor | Can have parameters | Only shared for all constants |
| Hierarchy | Bounded, sealed | Fixed set of constants |
Choosing between sealed class and enum class depends on the task. If variants carry no additional data — use enum. If each variant contains unique fields — use sealed class or sealed interface.
sealed types are used in Kotlin projects for a range of standard scenarios where type-safe modeling is required.
Each Compose screen can have a sealed class UiState describing all possible states: Idle, Loading, Content(data), Error(exception). A when expression guarantees all states are handled.
NetworkResult with variants Success, Error, Loading is a standard pattern in Kotlin projects with Retrofit and Ktor. Sealed class ensures safe handling of each request outcome.
sealed interface for navigation routes allows modules to declare their own routes while staying within a unified hierarchy. This eliminates errors with unknown routes at compile time.
According to KotlinConf (2025), sealed class and sealed interface are the foundation of type-safe design in modern Kotlin applications. They combine with data class to model complex domain structures without losing safety at compile time.
Frequently Asked Questions
All direct subclasses of a sealed class must be declared in the same file. The same rule applies to sealed interface — implementations in one file.
No, the single-file rule applies to sealed interface as well. All implementations must be in the file where the sealed interface is declared.
sealed interface has no state or constructor and allows multiple implementation. sealed class can have a constructor and shared state, but a class can only inherit one sealed class.
The compiler checks when completeness: if not all subclasses are handled, the code does not compile. This eliminates runtime errors and makes code safer.
Yes, a sealed class can have a constructor (private by default). All subclasses can pass parameters to this constructor via super().
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also