0Pricing
Kotlin Academy · Lesson

sealed class vs sealed interface: When to Use Each

Understand the difference between sealed classes and interfaces in Kotlin.

sealed class vs sealed interface: When to Use Each is a free Kotlin Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Sealed Types in Kotlin

Sealed classes and interfaces restrict the class hierarchy to a known set of subtypes, enabling exhaustive when expressions.

sealed class Basics

A sealed class restricts subclassing to the same package (Kotlin 1.5+) or same file.
sealed class Shape
class Circle(val radius: Double) : Shape()
class Rectangle(val w: Double, val h: Double) : Shape()
object Unknown : Shape()

sealed interface: More Flexible

sealed interface allows subtypes to extend other classes AND implement other interfaces simultaneously — sealed class can't.
sealed interface Result<out T>
data class Success<T>(val value: T) : Result<T>
data class Error(val ex: Exception) : Result<Nothing>

Key Differences

sealed class: subclasses can have constructors and state. sealed interface: subtypes can extend any class. Use sealed interface when you need more flexibility.
// sealed class subtype extends another class:
sealed interface Command
class MoveCommand(val dx: Int, val dy: Int) : Command, Serializable
class ResizeCommand(val scale: Double) : Command, Cloneable

Exhaustive when: No else Needed

When all sealed subtypes are covered, the when expression is exhaustive — no else needed, and the compiler enforces completeness.
fun area(shape: Shape): Double = when (shape) {
    is Circle -> Math.PI * shape.radius * shape.radius
    is Rectangle -> shape.w * shape.h
}  // no 'else' — compiler guarantees completeness

Adding a Subtype Breaks Existing when

Add a new sealed subtype and existing when expressions will fail to compile until updated. This is the main benefit.
// Add Triangle to Shape:
class Triangle(val base: Double, val height: Double) : Shape()
// Now the area() function above won't compile until
// a Triangle branch is added — safety net!

Sealed Classes with Common Properties

Declare shared properties in the sealed class.
sealed class NetworkResult {
    abstract val timestamp: Long
}
data class SuccessResult(val data: String, override val timestamp: Long) : NetworkResult()
data class FailureResult(val error: String, override val timestamp: Long) : NetworkResult()

Nested Sealed Types

Sealed subtypes can themselves be sealed for multi-level hierarchies.
sealed interface UiState
object Loading : UiState
sealed interface Loaded : UiState
data class Content(val items: List<String>) : Loaded
data class Empty(val hint: String) : Loaded
data class Failure(val error: String) : UiState

object Subtypes for No-State Variants

Use object for sealed subtypes that carry no state.
sealed class Direction
object North : Direction()
object South : Direction()
object East : Direction()
object West : Direction()

fun move(d: Direction) = when (d) {
    North -> y++
    South -> y--
    East -> x++
    West -> x--
}

Sealed + data class + object Together

Mix data class (for stateful subtypes) and object (for singletons) under a sealed type.
sealed class LoadState
object Idle : LoadState()
object Loading : LoadState()
data class Success(val count: Int) : LoadState()
data class Error(val msg: String) : LoadState()

When to Choose sealed class vs interface

Use sealed class when: all subtypes share common state. Use sealed interface when: subtypes need to extend different base classes or implement other interfaces.

Quick Check

What advantage does sealed interface have over sealed class?

Recap

sealed class/interface restricts the hierarchy to known types. when over sealed is exhaustive — no else needed. sealed interface allows subtypes to extend other classes. Use data class for stateful, object for stateless subtypes.

Frequently asked questions

Is the “sealed class vs sealed interface: When to Use Each” lesson free?

Yes — the full text of “sealed class vs sealed interface: When to Use Each” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “sealed class vs sealed interface: When to Use Each”?

Understand the difference between sealed classes and interfaces in Kotlin. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “sealed class vs sealed interface: When to Use Each” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. sealed class vs sealed interface: When to Use Each
  2. Exhaustive when with Sealed Hierarchies
  3. Modeling UI State with Sealed Classes
  4. Nesting and Combining Sealed Hierarchies
← Back to Kotlin Academy