Kotlin

What Is the Kotlin Enum Class? Explained Clearly

What Is the Kotlin Enum Class? Explained Clearly

Most Kotlin developers use enum classes daily without thinking twice. But a surprising number don’t know what they’re actually capable of beyond holding a list of constants.

So what is the Kotlin enum class, really? It’s a special class type that defines a fixed set of type-safe constants, where each constant is a full object with properties, methods, and the ability to implement interfaces. That goes well beyond what Java enums offered.

This article covers everything from basic declaration syntax to advanced patterns like serialization with kotlinx.serialization, exhaustive when matching, sealed class comparisons, and real-world uses in Android and Jetpack Compose. Whether you’re just picking up Kotlin or cleaning up a production codebase, you’ll walk away knowing exactly when (and when not) to reach for an enum class.

What is an Enum Class in Kotlin

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

A Kotlin enum class is a special class type that defines a fixed set of constants. Each constant is a single, unique instance of that class, created at compile time and reused throughout the program’s lifecycle.

You declare one with the enum class keywords followed by the class name. The constants go inside the body, separated by commas.

enum class Direction { NORTH, SOUTH, EAST, WEST } `

That’s it. Four constants, type-safe, no room for invalid values to sneak in.

Every enum constant automatically gets two properties: name (the string representation) and ordinal (its position in the declaration, starting from 0). So Direction.EAST.ordinal returns 2, and Direction.EAST.name returns "EAST".

If you’ve worked with Java enums before, the Kotlin version will feel familiar. But there are differences worth knowing. Kotlin requires the class keyword after enum, which Java doesn't. This isn't just syntax sugar. It reinforces that each enum in Kotlin is a full class with all the capabilities that come with it.

Google’s own data shows that 70% of the top 1,000 apps on the Play Store are written in Kotlin. Enum classes are one of the constructs developers use most often inside those codebases, especially for representing states, configuration flags, and navigation routes.

Why is Kotlin becoming the new Java?

Discover Kotlin statistics: Android adoption, multiplatform growth, developer satisfaction, and the modern language evolution from JetBrains.

Explore Kotlin Data →

JetBrains reports that 95% of top Android apps include some Kotlin code. Took me a while to realize just how dominant it’s become, but the numbers don’t lie.

The Kotlin compiler treats enum classes differently from regular classes in a couple of ways. It generates a static values() function (or the newer entries property) and a valueOf() function automatically. You don't write those yourself. The compiler also knows every possible constant at compile time, which becomes really useful with when expressions later.

Why Kotlin Uses “enum class” Instead of Just “enum”

Java uses the standalone enum keyword. Kotlin chose enum class to make the relationship explicit.

Every enum constant is an object. An instance of the class itself. By keeping “class” in the declaration, Kotlin signals that you can add constructors, properties, methods, and even implement interfaces. It’s not just a list of names.

This design choice aligns with how software development has trended toward stronger type systems over the past decade. The more the compiler can verify at build time, the fewer bugs reach production.

Enum Constants and Their Initialization

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

Each enum constant is an instance of the enum class. That’s the part most beginners miss. They treat enums like simple labels, but they’re actually objects with real constructor calls happening behind the scenes.

Enum Constructors with Parameters

You can define a primary constructor on your enum class and pass arguments to each constant.

` enum class HttpStatus(val code: Int, val description: String) { OK(200, "Success"), NOTFOUND(404, "Resource not found"), SERVERERROR(500, "Internal server error") } `

Now HttpStatus.NOTFOUND.code gives you 404. Clean and type-safe.

One rule catches people off guard: if your enum class has any members (properties, methods, or companion objects) beyond the constants themselves, you need a semicolon after the last constant. Without it, the compiler doesn’t know where the constant list ends and the class body begins.

` enum class Priority(val level: Int) { LOW(1), MEDIUM(2), HIGH(3); // semicolon required here

fun isUrgent(): Boolean = level >= 3 } `

Forgetting that semicolon is probably the most common Kotlin enum mistake. At least in my experience. The error message isn’t always obvious either.

Default Properties of Enum Constants

Every constant gets these for free, no setup needed:

  • name: Returns the exact string name of the constant as declared in code
  • ordinal: Returns the zero-based position in the declaration order

A word of caution on ordinal. If you reorder your constants, every ordinal value changes. Storing ordinals in a database is asking for trouble when someone rearranges the enum six months later. Store the name instead, or use a custom property like the code example above.

Properties and Methods Inside Enum Classes

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

Kotlin enum classes are not just constant containers. They hold state and behavior, which makes them genuinely useful beyond simple value representation.

You can declare custom properties in the class body, define shared methods, and even force each constant to provide its own implementation of an abstract method. This is where Kotlin enums pull ahead of what most developers expect from an enumerated type.

Custom Properties and Shared Methods

Stack Overflow’s 2024 survey ranked Kotlin as the 4th most admired programming language among developers. Part of that satisfaction comes from features like this, where a simple construct does more than you’d initially think.

` enum class Planet(val mass: Double, val radius: Double) { EARTH(5.972e24, 6.371e6), MARS(6.417e23, 3.389e6), JUPITER(1.898e27, 6.991e7);

fun surfaceGravity(): Double { val G = 6.674e-11 return G mass / (radius radius) } } `

Every constant shares the surfaceGravity() method. Call Planet.MARS.surfaceGravity() and you get the actual gravitational pull for Mars. The data and the logic live together.

Abstract Methods per Constant

Sometimes you need each constant to behave differently. Abstract methods make this possible.

` enum class Operation { ADD { override fun apply(a: Int, b: Int) = a + b }, SUBTRACT { override fun apply(a: Int, b: Int) = a - b }, MULTIPLY { override fun apply(a: Int, b: Int) = a * b };

abstract fun apply(a: Int, b: Int): Int } `

Each constant becomes an anonymous class that overrides the abstract function. The compiler enforces this. Miss one, and it won’t build.

This pattern replaces verbose if-else or when chains where you'd otherwise check which operation to run. The behavior is attached directly to the constant. Your mileage may vary on how far to push this pattern, but for two or three lines of logic per constant, it works great.

What you can’t do is define unique properties per individual constant (unless you use anonymous class overrides). Properties belong at the class level. If your constants need structurally different data, that’s usually the signal to consider a Kotlin data class or sealed class instead.

Enum Classes with Interfaces

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

Kotlin enum classes can implement one or more interfaces. They cannot extend other classes, because every enum already implicitly extends kotlin.Enum. But interfaces? Fair game.

Common Interface Implementation

The simplest approach is to provide one implementation shared across all constants.

` interface Printable { fun printFormatted(): String }

enum class LogLevel(val severity: Int) : Printable { DEBUG(0), INFO(1), WARN(2), ERROR(3);

override fun printFormatted() = “[$name] severity=$severity” } `

All four constants use the same printFormatted() logic. This is useful when you want to pass enum constants to functions that accept the interface type.

Per-Constant Interface Implementation

Each constant can also provide its own version of the interface methods. This is where things get interesting for strategy-pattern style implementations.

` interface Describable { fun describe(): String }

enum class Season : Describable { SPRING { override fun describe() = “Flowers bloom” }, SUMMER { override fun describe() = “Peak sunshine” }, FALL { override fun describe() = “Leaves change” }, WINTER { override fun describe() = “Snow falls” } } `

You get polymorphism with a fixed set of options. No open class hierarchies, no runtime surprises. The compiler knows every possible implementation at build time.

This pattern shows up a lot in Android development where view states or navigation destinations implement a common contract. Netflix, Pinterest, and Airbnb all use Kotlin in their Android apps, and patterns like these are standard across large codebases where compile-time safety matters.

Using “when” Expressions with Enum Classes

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

The when expression and enum classes are basically designed for each other in Kotlin. The compiler knows every constant in your enum, so it can verify at build time that you've handled all of them.

` enum class PaymentMethod { CREDITCARD, DEBITCARD, PAYPAL, CRYPTO }

fun processPayment(method: PaymentMethod): String = when (method) { PaymentMethod.CREDITCARD -> “Processing credit card” PaymentMethod.DEBITCARD -> “Processing debit card” PaymentMethod.PAYPAL -> “Redirecting to PayPal” PaymentMethod.CRYPTO -> “Generating wallet address” } `

No else branch needed. The compiler sees four constants and four branches. Done.

If someone adds a fifth constant later (say, BANKTRANSFER), every when expression that doesn't handle it will throw a compile error. That's the real power here. You literally can't forget a case.

Why This Beats if-else Chains

An if-else chain checking string values or integer codes gives you zero safety. Typo in a string? Silent failure. New value added? Nothing warns you.

Featurewhen + enumif-else chain
Compile-time exhaustivenessYesNo
Type safetyFullDepends on implementation
IDE auto-completionAll branches generatedManual
Maintenance riskCompiler catches missing casesSilent failures possible

JetBrains’ 2024 Developer Ecosystem survey found that 75% of Kotlin users express satisfaction with the language. Exhaustive when matching is consistently cited as one of the features people like most, because it catches the kind of bugs that would otherwise ship to production.

Practical Pattern: when with Data-Holding Enums

You can combine when with enums that carry data for cleaner logic flows.

` enum class Environment(val baseUrl: String) { DEV("https://dev.api.example.com"), STAGING("https://staging.api.example.com"), PROD("https://api.example.com") }

fun configureClient(env: Environment) = when (env) { Environment.DEV -> setupDebugLogging(env.baseUrl) Environment.STAGING -> setupPartialLogging(env.baseUrl) Environment.PROD -> setupMinimalLogging(env.baseUrl) } `

The enum holds the configuration data. The when expression routes the behavior. Everything is type-safe and exhaustive. This is a common pattern in back-end development with Kotlin and Spring Boot, where different environments need different configurations.

Built-in Functions: valueOf and entries

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

Every Kotlin enum class comes with two key utility functions baked in. You don’t declare them. The compiler generates them automatically.

valueOf(String)

What it does: converts a string to the matching enum constant.

` val status = HttpStatus.valueOf("NOTFOUND") // Returns HttpStatus.NOTFOUND `

The string must match exactly, case-sensitive. Pass in “notfound” and you get an IllegalArgumentException. No partial matching, no fuzzy logic.

Handling invalid strings safely is something you’ll want to plan for, especially when parsing data from API integrations or user input. A common approach:

` fun safeValueOf(name: String): HttpStatus? = HttpStatus.entries.find { it.name == name } `

Returns null instead of crashing. Much friendlier for production code.

entries vs. values()

This is where Kotlin 1.9 made a real change.

FunctionReturnsPerformanceIntroduced
values()New array every callAllocates memory each timeKotlin 1.0
entriesImmutable list (reused)No allocation overheadKotlin 1.9

The values() function creates a brand new array every single time you call it. In a tight loop or a frequently called function, that adds up. The garbage collector has to clean up all those arrays.

The entries property returns the same immutable EnumEntries list on every access. No new allocations. The Kotlin team introduced it specifically to fix the performance issue with values().

` // Old way (still works, but avoid in new code) for (status in HttpStatus.values()) { ... }

// New way (Kotlin 1.9+) for (status in HttpStatus.entries) { … } `

And there’s a related detail worth knowing. On Android, if your enum constants don’t use custom methods or complex features, ProGuard (or R8) can optimize them down to plain integers at runtime. You get type safety in your source code and integer performance in the compiled output. That’s a pretty good deal.

Kotlin 2.0 also introduced enumEntries() as a replacement for the older enumValues() generic function, following the same performance principle. If your project uses source control management and you're tracking a migration from older Kotlin versions, updating these calls is a quick win.

Enum Classes vs. Sealed Classes

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

This is the question that comes up in every Kotlin project eventually. Both constructs restrict the set of possible types. But they solve different problems, and picking the wrong one creates headaches down the road.

The core difference: enum constants are single instances. Sealed class subclasses can hold different data per instance.

CriteriaEnum ClassSealed Class
Instance countOne per constantMultiple per subclass
Per-constant dataSame structure for allDifferent structure per subclass
InheritanceCannot extend classesEach subclass can extend independently
when performanceUses tableswitch (faster)Uses instanceof checks
SerializationBuilt-in name/ordinalRequires polymorphic setup

When Enums Are the Better Choice

Use an enum class when every option shares the same shape. Days of the week, HTTP status codes, log levels, user roles. All constants, all fixed, all known at compile time.

Enum comparison in when expressions is faster because the JVM uses tableswitch under the hood. Sealed classes rely on type checks, which are slightly more expensive per evaluation.

On Android specifically, R8/ProGuard can optimize enum constants down to plain integers at runtime. Sealed classes don’t get this treatment. For apps sensitive to software scalability and memory footprint, this matters.

When Sealed Classes Win

Network response states are the classic example. A success carries data. An error carries a message. A loading state carries nothing. Three different shapes for three different outcomes.

` sealed class NetworkResult<out T> { data class Success<T>(val data: T) : NetworkResult<T>() data class Error(val message: String) : NetworkResult<Nothing>() object Loading : NetworkResult<Nothing>() } `

You can’t model this cleanly with an enum because each state needs structurally different data. The Kotlin compiler still provides exhaustive when checking, so you get the same safety guarantee.

Google Workspace adopted Kotlin (including both enums and sealed classes) across Gmail, Docs, and Calendar to keep iOS and Android experiences consistent, according to a KotlinConf 2025 presentation.

Serialization and Persistence of Enum Values

Enums travel between systems constantly. API responses, database columns, shared preferences, configuration files. How you serialize them determines whether your app breaks gracefully or catastrophically when something unexpected shows up.

JSON Serialization

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

kotlinx.serialization is the Kotlin-native option. Add @Serializable to your enum class and it works out of the box, serializing each constant by its name.

` @Serializable enum class Priority { LOW, MEDIUM, HIGH } `

Need custom JSON keys? Use @SerialName on individual constants. This is common when your backend uses lowercase or snakecase values that don't match Kotlin naming conventions.

` @Serializable enum class Priority { @SerialName("low") LOW, @SerialName("medium") MEDIUM, @SerialName("high") HIGH } `

Gson and Jackson both handle Kotlin enums too. Gson uses @SerializedName, Jackson uses @JsonValue. Same concept, different annotations.

Database Storage Patterns

Room (version 2.3 and above) includes built-in type converters for enums, automatically storing them as their string name. You don’t need to write a custom TypeConverter anymore for basic cases.

If you do need custom conversion (mapping enums to integer codes, for example), write a TypeConverter and register it with your database class. Just don’t store ordinals. Reordering constants silently corrupts every row that references the old positions.

Safe storage rule: always persist the name or a custom stable identifier. Never the ordinal.

Handling Unknown Values from External Sources

APIs change. New enum values get added on the server side before your mobile app updates. If your deserialization can’t handle an unknown value, the app crashes.

The standard fix: add an UNKNOWN constant as a fallback. Jackson supports @JsonEnumDefaultValue natively. With kotlinx.serialization and Gson, you'll need a custom serializer to catch unrecognized strings and map them to your fallback.

This kind of defensive coding matters most in mobile application development where you can’t force all users to update simultaneously. Old app versions will encounter new server values. Plan for it.

Common Patterns and Real-World Uses

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

Enum classes show up everywhere once you start looking. They’re not just for toy examples with colors and directions.

State Machines

Order status tracking is the textbook use case. An order moves through a fixed sequence: PLACED, CONFIRMED, SHIPPED, DELIVERED, CANCELLED.

` enum class OrderStatus { PLACED, CONFIRMED, SHIPPED, DELIVERED, CANCELLED;

fun canTransitionTo(next: OrderStatus): Boolean = when (this) { PLACED -> next == CONFIRMED || next == CANCELLED CONFIRMED -> next == SHIPPED || next == CANCELLED SHIPPED -> next == DELIVERED DELIVERED -> false CANCELLED -> false } } `

The transition logic lives inside the enum itself. No separate state machine class needed. Duolingo’s mobile team discussed using similar Kotlin patterns to manage app lifecycle states during their KotlinConf 2025 presentation.

Configuration and Environment Flags

Base URLs: DEV, STAGING, PROD with different endpoint strings attached.

Feature flags: enum constants holding boolean toggles that vary per build variant.

Logging levels: DEBUG, INFO, WARN, ERROR with severity integers for filtering.

These are patterns you’ll find in practically every production Kotlin project. They keep configuration type-safe and centralized instead of scattered across string constants.

Android-Specific Patterns

JetBrains’ Developer Ecosystem data shows Kotlin Multiplatform usage jumped from 7% to 18% between 2024 and 2025. As more teams share code across platforms, enum classes become the go-to for defining shared state contracts.

  • Navigation routes in Jetpack Compose, where each screen is an enum constant
  • View states (Loading, Success, Error) combined with when for exhaustive UI rendering
  • Room database type converters mapping enum constants to stored strings

Kotlin job postings surged 30% year-over-year in 2024 according to industry data. A solid understanding of how to apply enum class patterns in Android and cross-platform app development is something interviewers actively look for.

Mapping HTTP Status Codes

A compact pattern for RESTful API work:

` enum class ApiResult(val code: Int) { SUCCESS(200), CREATED(201), BADREQUEST(400), UNAUTHORIZED(401), NOTFOUND(404), SERVER_ERROR(500);

companion object { fun fromCode(code: Int): ApiResult? = entries.find { it.code == code } } } `

The companion object provides a factory method that maps raw integers back to type-safe constants. Clean, testable, and it plays nicely with whatever HTTP client you’re using.

Limitations of Kotlin Enum Classes

Enum classes are great for what they do. But they have real boundaries, and pushing past those boundaries creates brittle code.

No Class Inheritance

Every enum class implicitly extends kotlin.Enum. Kotlin's single-inheritance model means you can't extend anything else. Interfaces are fine. Abstract classes are not.

If your design requires a class hierarchy with shared base behavior, sealed classes or regular abstract classes are the way to go. Trying to force inheritance into an enum will just frustrate you.

Fixed at Compile Time

maxresdefault What Is the Kotlin Enum Class? Explained Clearly

You cannot add enum constants at runtime. The set is locked when the code compiles. If your values need to come from a database, a config file, or user input, enums are the wrong tool entirely.

This catches people who try to use enums for things like product categories (which marketing changes quarterly) or feature toggles (which get added and removed frequently during iterative software development). Use a regular class or a database-backed list instead.

Memory Considerations

ScenarioMemory ImpactRecommendation
Small enum (3–10 constants)NegligibleUse freely
Large enum (50+ constants)Each constant is an object on the heapConsider alternatives
Enum with heavy propertiesMultiplied per constantUse lazy initialization
Performance-critical Android pathsR8 may optimize to integersProfile before optimizing

For most applications, enum memory usage is a non-issue. But if you’re building something with hundreds of constants each holding complex objects, the overhead adds up. Profile first, optimize second.

No Generic Type Parameters on Constants

You can’t give individual enum constants their own generic types. The type parameter belongs to the class, not to individual constants.

This limitation shows up when trying to build type-safe result wrappers or event buses where each event type carries different payload shapes. Sealed classes with generic subclasses handle this cleanly. Enums simply can’t.

For teams following software development best practices, knowing these constraints upfront saves refactoring time later. Pick the right construct from the start, and the code stays clean as the project grows.

FAQ on What Is The Kotlin Enum Class

What is a Kotlin enum class used for?

A Kotlin enum class defines a fixed set of type-safe constants. It’s used to represent predefined options like states, categories, or configuration values. Each constant is an object instance of the class itself, with access to properties and methods.

How do you declare an enum class in Kotlin?

Use the enum class keywords followed by the class name. List your constants inside the body, separated by commas. Unlike Java, Kotlin requires the class keyword after enum, reinforcing that each constant is a full object.

Can Kotlin enum classes have properties and methods?

Yes. You can define a primary constructor with parameters, and each constant passes its own values. Methods declared in the class body are shared across all constants. You can also define abstract methods that each constant overrides individually.

What is the difference between enum class and sealed class in Kotlin?

Enum constants are single instances sharing the same structure. Sealed class subclasses can hold different data per type. Use enums for fixed constant sets. Use sealed classes when each option needs structurally different properties or behaviors.

How does the “when” expression work with Kotlin enums?

The Kotlin compiler knows every constant in your enum. When you use a when expression, it checks that all cases are handled. No else branch needed. Adding a new constant without updating when triggers a compile error.

What is the difference between entries and values() in Kotlin enums?

The values() function creates a new array on every call. The entries property (Kotlin 1.9+) returns a reusable immutable list with zero allocation overhead. New projects should use entries for better performance.

Can Kotlin enum classes implement interfaces?

Yes. Enum classes can implement one or more interfaces. You can provide a shared implementation for all constants or let each constant override interface methods individually. They cannot extend other classes, since they already extend kotlin.Enum.

How do you serialize Kotlin enum values to JSON?

With kotlinx.serialization, add @Serializable to your enum class. Constants serialize by name by default. Use @SerialName for custom JSON keys. Gson and Jackson also support Kotlin enums with their own annotation systems.

Are Kotlin enum classes suitable for Android development?

Absolutely. Enum classes are widely used in Android development for navigation routes, view states, Room database columns, and configuration flags. R8 can even optimize simple enums to integers at runtime, reducing memory overhead.

What are the limitations of Kotlin enum classes?

They cannot inherit from other classes, only implement interfaces. Constants are fixed at compile time, so they can’t be extended at runtime. They also don’t support generic type parameters on individual constants. Use sealed classes for those cases.

Conclusion

Understanding what is the Kotlin enum class goes beyond memorizing syntax. It means knowing when to reach for enums over sealed classes, how to serialize them safely with kotlinx.serialization or Gson, and where they fit inside a production Android project built with Jetpack Compose.

Enum classes give you compile-time safety through exhaustive when matching. They hold properties, implement interfaces, and work smoothly with Room database type converters. The newer entries property in Kotlin 1.9 fixes the old performance problem with values()`.

But they have limits. No inheritance, no runtime extension, no per-constant generics.

Pick the right tool. Use enums for fixed, predictable sets of constants. Use sealed classes when your types need different data shapes. That single decision will save you refactoring time as your Kotlin codebase grows.

50218a090dd169a5399b03ee399b27df17d94bb940d98ae3f8daff6c978743c5?s=250&d=mm&r=g What Is the Kotlin Enum Class? Explained Clearly

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.