Sparround

data, sealed, object, enum — when to use which

Kotlin's special class kinds are an interview favorite because each encodes a design intent:

  • data class — a value carrier: equals/hashCode/toString/copy/componentN are generated automatically (only over primary constructor properties).
  • sealed class / sealed interface — a restricted hierarchy: all subtypes are known at compile time, so when becomes exhaustive.
  • object — the language's built-in singleton: thread-safe, lazily initialized.
  • companion object — static-like members tied to a class, the typical home of factory methods.
  • enum class — a fixed set of constants; each constant can hold state and override methods.
Questionsealed classenum class
Can each variant carry its own data?Yes — each subclass with different propertiesLimited — all constants share the same fields
Instance countAny number per subtypeExactly one per constant
Typical useUI state, API results (Success/Error/Loading)Fixed lists: currency, status codes

Classic interview question: "How would you model an API response?" The expected answer is a sealed class: Success(data), Error(code, message), Loading. Because when is exhaustive, adding a new case makes the compiler flag every usage site — in a banking app this prevents forgotten error-handling branches.

🛠 Practice task

Model a payment outcome: a sealed interface PaymentResult with Success, Declined and NetworkError variants (each carrying different data).

  • Write a handler with when and no `else` — the compiler should be satisfied.
  • Now add a Pending variant and see where the compiler flags you.
  • Try building the same model as an enum class and write down what becomes impossible.

Done when: you can answer "why sealed, not enum" using your own example.

📚 Sources and documentation