skip to content

What is a sealed class (or sealed interface) in Kotlin, and what does the sealed modifier guarantee about its subtypes?

level: juniorimportance: must knowfreq 80%

answer

  1. Closed set of subtypes, known at compile time
  2. sealed class is implicitly abstract — instantiate subtypes
  3. Outside code cannot add new subtypes
  4. Subtypes can be data class / object / sealed
  5. Enables exhaustive when without else

basics

~20 s

A sealed class or interface is one where the compiler knows the complete, fixed list of all its direct subtypes. New subtypes can't be added from outside, so the set of possibilities is closed and known at compile time.

solid answer

~40 s

The sealed modifier marks a class or interface as a restricted hierarchy: the compiler knows every direct subtype at compile time, and no outside code can add more. A sealed class is also implicitly abstract, so you cannot instantiate it directly; you instantiate one of its subclasses. Subtypes must live in the same module and same package as the sealed declaration (the permitted-subtype rule). Sealed interfaces work the same way but, being interfaces, allow a type to implement several of them. The closed-set guarantee is what makes a when over the type exhaustive without an else branch. Typical subtypes are data classes, objects, or further sealed types. Compared to an enum, each subtype can hold its own distinct state and you can have multiple instances of a subtype.

code

kotlin · 8 lines
kotlin
sealed class PaymentMethod {
    data class Card(val last4: String) : PaymentMethod()
    data class Bank(val iban: String) : PaymentMethod()
    object Cash : PaymentMethod()
}

// PaymentMethod() // compile error: cannot create instance of sealed class
val pm: PaymentMethod = PaymentMethod.Cash

go deeper

for a junior

Can define a sealed class with a couple of subtypes and explain the closed-set idea in plain words.

for a middle

Knows it's implicitly abstract, distinguishes sealed class vs sealed interface, and connects the closed set to compiler exhaustiveness.

for a senior

Frames sealed as a restricted hierarchy used to model fixed alternatives and contrasts it precisely with open hierarchies and enums.

for a principal

Articulates the design intent — encoding invariants in the type system so illegal states are unrepresentable and changes are compiler-verified.

## What 'sealed' means The `sealed` keyword is a class/interface modifier that creates a **closed (restricted) type hierarchy**. 'Closed' means the compiler can see the *complete* set of direct subtypes at compile time, and nothing outside the declaration's allowed location can introduce new ones. ```kotlin sealed interface Shape data class Circle(val radius: Double) : Shape data class Rectangle(val width: Double, val height: Double) : Shape object Unknown : Shape ``` Here `Shape` has exactly three direct subtypes. No other file or library can add a fourth implementer. ## Key properties - **Implicitly abstract (for sealed *class*):** A `sealed class` cannot be instantiated directly — `Shape()` would not compile if `Shape` were a class. You create instances of its subtypes instead. Its constructors are effectively `protected` by default. - **A sealed *interface* is just an interface** with a closed implementer set. Because interfaces support multiple inheritance, one type can implement several sealed interfaces. - **Compile-time-known subtype set:** Because the set is fixed, the compiler can reason about completeness — this is what enables an exhaustive `when` without an `else`. - **Subtypes are normal types:** They can be `data class`, `object`, regular `class`, or even another `sealed` type, and each can carry its own state and behavior. ## Why use it Sealed types model 'one of a fixed set of things' — a value is *exactly one* of the known subtypes. This gives you type-safe alternatives that the compiler can check, unlike an open class hierarchy where any subtype could appear. ## Sealed vs open A plain `open class` or ordinary `interface` is **open**: any number of unknown subtypes can exist anywhere. `sealed` deliberately removes that openness to gain compile-time knowledge of the whole hierarchy.

  • Can you instantiate a sealed class directly?
    No. A sealed class is implicitly abstract; you instantiate one of its subtypes. A sealed interface also can't be instantiated since interfaces never can.
  • Does a sealed type prevent subclassing entirely?
    No — it restricts *who* can subclass and *where*. Subtypes are still allowed, but only within the same module and package as the sealed declaration.

Like a multiple-choice question with a fixed list of answers — the answer must be one of the printed options, and nobody can scribble in a new one.

saying these in an interview costs you the question

  • Saying a sealed class has no subtypes / can't be extended at all
  • Claiming you can instantiate a sealed class directly with its constructor
  • Thinking sealed means the same as final
  • Confusing sealed with enum (only one value per case)

context