What Is the Kotlin Enum Class? Explained Clearly

Ever needed a way to represent a fixed set of related values in your code? The Kotlin enum class solves this problem elegantly. As a core feature of the JetBrains Kotlin language, enums provide type-safe constants with rich functionality that goes far beyond simple value lists.
Kotlin enumeration classes combine the best of Java enums with Kotlin’s expressive syntax, creating a powerful tool for mobile app development, server-side programming, and multiplatform projects. Unlike plain constants, enum classes in Kotlin can:
- Carry properties and state
- Implement interfaces
- Contain methods with custom behavior
- Provide built-in utility functions
Whether you’re building Android applications, implementing state machines, or designing clean domain models, understanding Kotlin enum class syntax and capabilities is essential for writing maintainable code.
This guide explores everything from basic enum declaration to advanced patterns like anonymous class implementations and sealed class alternatives, helping you leverage the full potential of Kotlin’s type-safe enums.
What Is the Kotlin Enum Class?
The Kotlin enum class is a special class used to define a fixed set of constants. Each enum constant is an object, and you can add properties or methods to them. Enums in Kotlin are type-safe and useful for representing a group of related values like directions, states, or modes.
Creating and Using Basic Enum Classes

Syntax for Defining Enum Classes
Basic Enum Declaration
Kotlin enum class offers a way to define a type-safe set of constants. Let’s jump right in.
enum class Direction {
NORTH, SOUTH, EAST, WEST
}
That’s it. Simple. The Kotlin programming language makes enum creation straightforward compared to Java enum.
Each constant (NORTH, SOUTH, etc.) is an instance of the Direction class. These enum constants in Kotlin exist as singleton objects, created when your program loads.
Adding Properties to Enum Constants
Enums become more useful with custom properties:
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
Here, each constant holds an RGB value. The Kotlin enum class syntax requires defining a primary constructor when adding properties. You can access these values directly:
val redValue = Color.RED.rgb // 0xFF0000
Adding Methods to Enum Classes
With JetBrains Kotlin language, enums can include methods:
enum class Temperature(val celsius: Int) {
FREEZING(0),
WARM(25),
HOT(40);
fun toFahrenheit(): Int = celsius * 9/5 + 32
}
Notice the semicolon after the last constant. Required when adding methods or properties to the class body.
Working with Enum Constants
Accessing Enum Constants
Get an enum constant by direct reference:
val direction = Direction.NORTH
Kotlin smart cast with enum works automatically. The compiler knows exactly which type you’re dealing with.
Iterating Through All Values
Enum class valueOf() function Kotlin provides isn’t the only utility. You can loop through all constants:
for (direction in Direction.values()) {
println(direction)
}
This feature prints:
NORTH
SOUTH
EAST
WEST
Converting Strings to Enum Constants
Convert a string to an enum using valueOf():
val direction = Direction.valueOf("NORTH") // Returns Direction.NORTH
Be careful. If the string doesn’t match any constant, valueOf() throws IllegalArgumentException. In Android development, this might crash your app.
// Safer approach with try/catch
try {
val direction = Direction.valueOf(userInput.toUpperCase())
// Use direction
} catch (e: IllegalArgumentException) {
// Handle invalid input
}
Built-in Enum Properties and Methods
The Name Property
Every enum has a name property:
val directionName = Direction.NORTH.name // "NORTH"
This returns the exact name used in the declaration, useful for serialization.
The Ordinal Property
Enum ordinal Kotlin provides tells you the position:
val index = Direction.EAST.ordinal // 2 (zero-based index)
Avoid relying on ordinal for business logic. It’s fragile. Order might change.
The Values() and ValueOf() Methods
These methods come built-in:
// Get all constants
val allDirections = Direction.values() // Array of all Direction values
// Find by name
val direction = Direction.valueOf("WEST") // Direction.WEST
The values() method returns a new array each time. In performance-critical contexts, cache this result.
Advanced Enum Features in Kotlin
Adding Custom Properties
Kotlin enum properties can be more complex than simple values:
enum class Planet(
val mass: Double, // kg
val radius: Double // km
) {
EARTH(5.97e24, 6371.0),
MARS(6.42e23, 3389.5),
VENUS(4.87e24, 6051.8);
// Derived property with custom getter
val surfaceGravity: Double
get() {
val G = 6.67e-11 // Gravitational constant
return G * mass / (radius * radius)
}
}
Enum class constructors Kotlin supports make this possible. You can define calculated properties with custom getters.
Implementing Interfaces with Enums
Kotlin enum class with interfaces offers powerful flexibility:
interface Describable {
fun describe(): String
}
enum class Day : Describable {
MONDAY {
override fun describe() = "Start of work week"
},
TUESDAY {
override fun describe() = "Second day"
},
WEDNESDAY {
override fun describe() = "Middle of week"
};
}
Each constant must implement the interface methods. This pattern enforces type-safe enums while providing polymorphic behavior.
Using Anonymous Classes in Enums
The anonymous class in Kotlin enum feature lets constants override methods:
enum class Operation(val symbol: String) {
ADD("+") {
override fun apply(x: Int, y: Int) = x + y
},
SUBTRACT("-") {
override fun apply(x: Int, y: Int) = x - y
},
MULTIPLY("*") {
override fun apply(x: Int, y: Int) = x * y
},
DIVIDE("/") {
override fun apply(x: Int, y: Int) = x / y
};
abstract fun apply(x: Int, y: Int): Int
}
With abstract methods in Kotlin enum, each constant must provide its implementation. This pattern resembles the strategy pattern in object-oriented programming.
The Kotlin enum when expression works beautifully with these enhanced enums:
fun calculate(x: Int, y: Int, op: Operation): Int {
return when(op) {
Operation.ADD -> x + y
Operation.SUBTRACT -> x - y
Operation.MULTIPLY -> x * y
Operation.DIVIDE -> x / y
}
}
But using the enum’s built-in method is cleaner:
fun calculate(x: Int, y: Int, op: Operation): Int {
return op.apply(x, y)
}
Kotlin enum class in domain models often uses these patterns for business logic. They’re readable. Maintainable. Safe.
Enum inheritance limitations mean enums can’t extend other classes, but they can implement multiple interfaces. This makes them perfect for representing fixed sets of related behaviors.
The IntelliJ IDEA editor provides excellent support for navigating enum implementations in complex projects. Kotlin’s type safety ensures you never miss implementing a required method.
Practical Applications of Kotlin Enums
State Management
Kotlin enum class is perfect for state management. States are finite and predictable.
enum class OrderStatus {
CREATED,
PROCESSING,
SHIPPED,
DELIVERED,
CANCELED
}
This creates a type-safe representation of possible states. The compiler catches invalid states at compile time, not runtime.
For more complex state transitions, add structure:
enum class TaskState(val isTerminal: Boolean) {
TODO(false),
IN_PROGRESS(false),
REVIEW(false),
DONE(true),
CANCELED(true);
fun canTransitionTo(newState: TaskState): Boolean = when(this) {
TODO -> newState == IN_PROGRESS || newState == CANCELED
IN_PROGRESS -> newState == REVIEW || newState == CANCELED
REVIEW -> newState == DONE || newState == IN_PROGRESS
DONE, CANCELED -> false
}
}
Using enum class for state management in Kotlin Android apps enforces clean, predictable behavior. The state machine pattern works exceptionally well with enums.
Data Validation and Processing
Enums excel at input validation:
enum class FileType(val extension: String, val mimeType: String) {
PDF(".pdf", "application/pdf"),
DOCX(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
XLSX(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
JPG(".jpg", "image/jpeg"),
PNG(".png", "image/png");
companion object {
fun fromExtension(ext: String): FileType? {
return values().find { it.extension.equals(ext, ignoreCase = true) }
}
}
}
Kotlin enum companion object provides static-like behavior. This pattern enables validating file extensions against known types.
Data transformation benefits from enum properties:
enum class Currency(val symbol: String, val code: String) {
USD("$", "USD"),
EUR("€", "EUR"),
GBP("£", "GBP"),
JPY("¥", "JPY");
fun format(amount: Double): String {
return when(this) {
JPY -> "$symbol${amount.toInt()}"
else -> "$symbol${"%.2f".format(amount)}"
}
}
}
The enum pattern matching in Kotlin makes formatting context-specific.
Configuration and Settings
Application settings benefit from enums:
enum class Theme {
LIGHT, DARK, SYSTEM;
fun applyToActivity(activity: Activity) {
when(this) {
LIGHT -> activity.setTheme(R.style.AppTheme_Light)
DARK -> activity.setTheme(R.style.AppTheme_Dark)
SYSTEM -> {
// Apply based on system settings
}
}
}
}
Feature flags become more manageable with enums:
enum class FeatureFlag(val isEnabled: Boolean, val minVersion: Int) {
NEW_UI(true, 12),
DARK_MODE(true, 10),
EXPERIMENTAL_CAMERA(false, 15);
fun isAvailableForVersion(appVersion: Int): Boolean {
return isEnabled && appVersion >= minVersion
}
}
Kotlin enum implementation allows easy modification when features graduate from experimental to standard.
Localizing enum values is straightforward:
enum class ErrorCode(val code: Int) {
NOT_FOUND(404),
SERVER_ERROR(500),
FORBIDDEN(403);
fun getLocalizedMessage(context: Context): String {
return context.getString(when(this) {
NOT_FOUND -> R.string.error_not_found
SERVER_ERROR -> R.string.error_server
FORBIDDEN -> R.string.error_forbidden
})
}
}
Best Practices for Kotlin Enum Classes
Design Guidelines
Keep enums focused. They should represent a single concept with a finite set of instances.
// Good: Focused on direction
enum class Direction { NORTH, SOUTH, EAST, WEST }
// Bad: Mixes concepts
enum class Status { SUCCESS, ERROR, NORTH, SOUTH }
When to use enum vs sealed class in Kotlin? Use enums for truly finite sets of instances where each instance is effectively a singleton. Use sealed classes when:
- Instances need to hold varying data
- Inheritance is needed
- The set might expand in future versions
Kotlin sealed enum pattern combines both approaches:
sealed class Result {
object Success : Result()
data class Error(val message: String) : Result()
data class Loading(val progress: Float) : Result()
}
Naming conventions matter:
- Enum class names: Pascal case and singular (Direction, not Directions)
- Constants: SCREAMING_SNAKE_CASE
- Properties: camelCase
Kotlin style guide recommends these conventions consistently.
Performance Considerations
Enum classes are memory-efficient. Each instance exists only once. Still, be aware of memory usage:
// Potentially wasteful if rarely used
enum class HttpStatusCode(val code: Int, val message: String) {
// Hundreds of HTTP codes with messages
}
// Better approach for large sets
object HttpStatusCodes {
fun getMessage(code: Int): String = when(code) {
// Lookup implementation
}
}
Serialization of enum classes in Kotlin should be handled carefully. By default, most serialization libraries use names:
@Serializable
enum class Priority { LOW, MEDIUM, HIGH }
Use custom serializers when you need backward compatibility:
@Serializable(with = PrioritySerializer::class)
enum class Priority(val value: Int) {
LOW(0), MEDIUM(1), HIGH(2);
}
In Android development, enums have gotten a bad reputation for performance. Modern Kotlin compilers optimize well, but if you’re targeting older Android versions, consider alternatives for very large enums:
// Instead of large enums, use int constants with annotations
@IntDef(value = [PRIORITY_LOW, PRIORITY_MEDIUM, PRIORITY_HIGH])
annotation class Priority
const val PRIORITY_LOW = 0
const val PRIORITY_MEDIUM = 1
const val PRIORITY_HIGH = 2
Testing Enum Classes
Unit testing strategies for enums should cover all constants:
@Test
fun `test all planets have positive mass`() {
for (planet in Planet.values()) {
assertTrue(planet.mass > 0)
}
}
Test enum-based logic systematically:
@Test
fun `test state transitions`() {
// Valid transitions
assertTrue(TaskState.TODO.canTransitionTo(TaskState.IN_PROGRESS))
assertTrue(TaskState.IN_PROGRESS.canTransitionTo(TaskState.REVIEW))
// Invalid transitions
assertFalse(TaskState.TODO.canTransitionTo(TaskState.DONE))
assertFalse(TaskState.DONE.canTransitionTo(TaskState.IN_PROGRESS))
}
The enum class in Kotlin coroutines context becomes more important as libraries adopt this pattern. Test enum interactions with coroutines using runTest
:
@Test
fun `test async processing with file types`() = runTest {
val result = processFile("document.pdf")
assertEquals(FileType.PDF, result.fileType)
}
Mocking enums in tests is rarely needed since they’re static. But mock objects that use enums:
// Mocking a repository that works with enums
val mockRepo = mockk<TaskRepository>()
coEvery { mockRepo.updateTaskState(any(), TaskState.DONE) } returns Unit
Kotlin multiplatform projects benefit from enums’ consistency across targets. Use enums to ensure consistent behavior between platforms.
Mobile app development with Kotlin has embraced enums for their safety and expressiveness. Spring Boot with Kotlin similarly leverages enums for configuration, validation, and business rules.
The Kotlin community forums often discuss advanced enum techniques. The approach continues to evolve with each new Kotlin version.
Comparing Enums with Alternatives
Enums vs Constants
The choice between enum class and constant values isn’t always clear. Let’s break it down.
// Using constants
const val STATUS_ACTIVE = "active"
const val STATUS_INACTIVE = "inactive"
const val STATUS_PENDING = "pending"
// Using enum
enum class Status {
ACTIVE, INACTIVE, PENDING
}
When to use enum instead of const vals? Type safety is the key difference. Constants let you pass any string, while enums restrict values to the defined set.
// With constants - no type checking!
fun processStatus(status: String) {
// Might get passed invalid strings at runtime
}
// With enums - compiler ensures valid values
fun processStatus(status: Status) {
// Can only receive valid Status values
}
Feature comparison highlights other advantages:
- Discoverability – IDE shows all enum options when typing
- Namespace – Enums group related constants
- Functionality – Enums can have properties and methods
- Serialization – Most libraries handle enums elegantly
Kotlin type-safe enums prevent entire classes of bugs. One bad string can crash your app. Enums eliminate this risk.
// Dangerous with constants
if (status == "ACTVE") { // Typo!
// Logic never runs
}
// Safe with enums
if (status == Status.ACTIVE) { // IDE autocomplete prevents typos
// Logic runs as expected
}
JetBrains Kotlin language makes using enums almost as lightweight as constants. The performance difference is negligible in most applications.
Enums vs Sealed Classes
Sealed classes provide another way to represent restricted type hierarchies. The structural differences are significant.
// Enum approach
enum class Result {
SUCCESS, ERROR, LOADING
}
// Sealed class approach
sealed class Result {
object Success : Result()
data class Error(val message: String) : Result()
data class Loading(val progress: Float) : Result()
}
Kotlin sealed enum pattern combines traits of both. Use case differences determine which to choose:
- Fixed vs Variable Data – Enums have fixed instances with fixed data, sealed classes can have different data per instance
- Number of Instances – Enums have a fixed, known number of instances; sealed classes can have unlimited instances of each subtype
- Runtime Creation – Enum instances exist at compile time; sealed class instances can be created at runtime
When to choose one over the other? Ask these questions:
- Do instances need to hold different types of data? → Sealed class
- Do you need runtime instance creation? → Sealed class
- Do you need to iterate through all possible values? → Enum
- Is the set truly fixed and limited? → Enum
The Kotlin/Native implementation optimizes both approaches well. For simple state representation without varying data, enum is more concise.
Real-world example:
// Payment method as enum - limited options, fixed data structure
enum class PaymentMethod(val displayName: String) {
CREDIT_CARD("Credit Card"),
PAYPAL("PayPal"),
BANK_TRANSFER("Bank Transfer")
}
// Payment status as sealed class - needs to carry different data per state
sealed class PaymentStatus {
object Pending : PaymentStatus()
data class Processing(val estimatedMinutes: Int) : PaymentStatus()
data class Completed(val transactionId: String) : PaymentStatus()
data class Failed(val errorCode: Int, val message: String) : PaymentStatus()
}
The Kotlin enum class in clean architecture often works alongside sealed classes. They serve complementary purposes.
Enums vs Data Classes
Fixed vs dynamic instances represent the core difference between these types. Data classes create new instances at runtime. Enum instances exist at compile time.
// Enum
enum class Priority(val value: Int) {
LOW(0), MEDIUM(1), HIGH(2)
}
// Data class
data class Priority(val name: String, val value: Int)
// Usage
val low = Priority.LOW // Enum: reference existing instance
val low = Priority("LOW", 0) // Data class: create new instance
Feature comparison reveals important differences:
Feature | Enum | Data Class |
---|---|---|
Fixed set of values | Yes | No |
Runtime instance creation | No | Yes |
Singleton guarantee | Yes | No |
Values() method | Yes | No |
Pattern matching completeness | Yes | No |
Equality checking | Reference equality | Content equality |
Enum class entry points in Kotlin often interact with data classes. They work well together:
enum class TaskType { BUG, FEATURE, REFACTOR }
data class Task(
val id: String,
val title: String,
val type: TaskType,
val assignee: String
)
This combination leverages the strengths of both. The enum provides a controlled vocabulary, while the data class manages the variable information.
Kotlin enum initialization blocks can add sophisticated behavior to enum constants:
enum class LogLevel(val level: Int) {
DEBUG(0) {
init {
if (BuildConfig.RELEASE) {
throw IllegalStateException("DEBUG not allowed in RELEASE")
}
}
},
INFO(1),
WARNING(2),
ERROR(3);
}
The enum class deserialization in Kotlin usually works automatically with libraries like Gson, Moshi, or kotlinx.serialization. Data classes require more configuration for special cases.
Object-oriented programming with Kotlin gets cleaner when using enums for their intended purpose. The functional programming aspects of Kotlin work with both constructs seamlessly.
The Kotlin/JS implementation optimizes enum usage, making it efficient even in browser contexts. Using the right tool for the job matters across all Kotlin platforms.
Kotlin code examples often combine these approaches based on specific needs. The Kotlin official website documentation demonstrates these patterns clearly. Server-side Kotlin applications typically use a mix of enums, sealed classes, and data classes for different aspects of domain modeling.
Kotlin learning resources frequently highlight these distinctions to help developers make informed decisions. The Kotlin enum class documentation specifically notes when alternatives might be more appropriate.
Android Studio provides excellent tooling for all these types, with special visualization for enum relationships. The enum state machine pattern, in particular, benefits from IDE support for navigation between states.
Mobile app development teams often establish guidelines on when to use each option. Having a consistent approach improves codebase clarity.
FAQ on The Kotlin Enum Class
What exactly is a Kotlin enum class?
A Kotlin enum class is a special type that represents a fixed set of constants. Unlike Java enum, the Kotlin enumeration class is a full-featured class that can contain properties, methods, and implement interfaces while maintaining type safety. Each enum constant exists as a single instance, making them perfect for representing categories, states, or commands.
Can enum classes in Kotlin have properties?
Yes. Kotlin enum properties are defined through constructors:
enum class Planet(val mass: Double, val radius: Double) {
EARTH(5.97e24, 6371.0),
MARS(6.42e23, 3389.5)
}
Access them directly with Planet.EARTH.mass
. Properties make enums more powerful than simple constants.
How do I iterate through all enum values in Kotlin?
Use the built-in values()
method:
for (direction in Direction.values()) {
println(direction.name)
}
This returns an array containing all enum constants in their declaration order. The Kotlin Standard Library provides this automatically for all enum classes.
Can enum classes implement interfaces?
Absolutely. The Kotlin enum class with interfaces feature is powerful:
interface Clickable { fun onClick() }
enum class Button : Clickable {
OK { override fun onClick() { println("OK clicked") } },
CANCEL { override fun onClick() { println("Canceled") } }
}
Each constant can provide its own implementation.
What’s the difference between enum and sealed class in Kotlin?
Enums have a fixed set of instances that exist at compile time. Sealed classes allow different data per subclass and runtime instance creation. Use enum class for truly fixed sets with identical structure; use sealed classes when subtypes need different properties or when instances vary at runtime.
Can enum constants have different behavior?
Yes, with anonymous class in Kotlin enum:
enum class Operation {
PLUS { override fun apply(x: Int, y: Int) = x + y },
MINUS { override fun apply(x: Int, y: Int) = x - y };
abstract fun apply(x: Int, y: Int): Int
}
Each constant overrides the abstract method with custom behavior.
How do I convert a string to an enum in Kotlin?
Use the valueOf()
method:
val direction = Direction.valueOf("NORTH") // Returns Direction.NORTH
Be careful—this throws IllegalArgumentException
if the string doesn’t match any constant. For safer conversion, use values().find { it.name == str }
or enum class custom functions.
What built-in properties do Kotlin enums have?
Every enum constant has:
name
: String name of the constantordinal
: Int position in the declaration (zero-based)
These properties help with serialization and ordering. Kotlin enum name property is particularly useful for display purposes.
When should I use enums instead of constants in Kotlin?
Use enums when you need:
- Type safety (compiler verification)
- Related properties or behavior
- To iterate through all possible values
- Pattern exhaustiveness checks with
when
The enum class in Kotlin multiplatform projects ensures consistent behavior across platforms. Constants can’t provide these benefits.
Can I use Kotlin enums with when expressions?
Yes, and it’s a perfect match! The Kotlin when expression with enums provides compile-time exhaustiveness checking:
when (day) {
Day.MONDAY -> startWeek()
Day.FRIDAY -> endWeek()
Day.SATURDAY, Day.SUNDAY -> weekend()
else -> regularDay() // Required only if Day enum might have more values
}
The compiler enforces handling all cases.
Conclusion
Understanding what is the Kotlin enum class gives developers a powerful tool for creating type-safe, maintainable code. The enum class pattern in Kotlin delivers benefits far beyond simple constants, combining Java’s safety with Kotlin’s expressiveness. Enum class default implementations save time while promoting code consistency.
Key takeaways from our exploration:
- Enum classes provide compile-time safety that prevents entire categories of bugs
- Kotlin enum initialization blocks enable sophisticated validation during class loading
- The enum class for state management pattern simplifies complex application workflows
- Kotlin declarative enum definition works seamlessly with modern functional approaches
- Abstract methods in Kotlin enum create polymorphic behavior without inheritance complexity
As your Kotlin projects grow in complexity, applying these enum techniques will improve code readability and maintainability. From Android development to server-side Kotlin applications, enums remain an essential part of the Kotlin type system. The flexibility to implement interfaces, override methods, and carry state makes them indispensable in your programming toolkit.
- What Is Gitignore? Understand It in 5 Minutes - May 22, 2025
- Why Embedded Systems Are Crucial for Modern Product Success - May 22, 2025
- What Is MVC? Understanding the Classic Software Pattern - May 21, 2025