How to Declare and Use a Variable of an Enum Type in Kotlin: A Complete Guide
To declare and use a variable of an enum type in Kotlin, define an enum class with constants, then assign a specific constant to a variable typed with that enum class, allowing you to access properties like name and ordinal or use it in when expressions.
Kotlin's enum implementation is defined in the JetBrains/kotlin repository, where every enum class automatically extends the platform-agnostic Enum<E> base class found in libraries/stdlib/src/kotlin/Enum.kt. This design generates standard members like values() and entries while allowing the compiler to optimize enum usage across JVM, Native, JS, and WASM targets.
Understanding Kotlin's Enum Implementation
The Enum Base Class and Platform Abstraction
In libraries/stdlib/src/kotlin/Enum.kt, Kotlin declares Enum<E> as an expect class. This means each platform (JVM, JavaScript, Native) provides its own actual implementation while maintaining a consistent API. For example, the Native implementation resides in kotlin-native/runtime/src/main/kotlin/kotlin/Enum.kt.
This abstraction allows the Kotlin compiler to treat enum types as sealed classes with a fixed set of instances, enabling exhaustive when checks and optimized memory layout on different platforms.
Compiler-Generated Members for Enum Types
When you declare an enum class, the compiler automatically generates several members based on the definitions in libraries/stdlib/src/kotlin/enums/EnumEntries.kt and related intrinsic functions:
name: String— The exact identifier used in the source codeordinal: Int— Zero-based position of the constant in the declarationvalues(): Array<E>— Returns a new array containing all constants (allocates fresh array on each call)valueOf(name: String): E— Looks up a constant by name, throwingIllegalArgumentExceptionif not foundentries: EnumEntries<E>— An immutable list view introduced in Kotlin 1.9 that avoids allocation on repeated access
The JVM-specific implementation of these generators can be found in compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt, which handles the IR lowering that emits platform-specific bytecode for values() and entries.
How to Declare an Enum Class in Kotlin
To declare an enum type, use the enum class keyword followed by the constant definitions. You can include properties, methods, and even implement interfaces. The following example is adapted from the test suite at plugins/kapt/kapt-compiler/testData/converter/enums.kt:
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
// Instance method available on any Color variable
fun hex() = "#%06X".format(rgb)
}
Each enum entry is a singleton object of type Color. The compiler generates a final class Color that extends Enum<Color>, making RED, GREEN, and BLUE the only possible instances of this type.
How to Declare and Use a Variable of an Enum Type
Mutable and Immutable Enum Variables
Once you have defined an enum class, you can declare variables using the enum type as you would any other class. The type system ensures that only valid enum constants can be assigned:
// Mutable variable that can be reassigned
var current: Color = Color.RED
// Immutable reference that cannot change
val favorite = Color.BLUE
The explicit type annotation : Color on the var declaration is optional when the initializer is present, but including it improves readability and IDE navigation. Because Color extends Enum<Color>, these variables have access to all standard enum properties.
Accessing Enum Properties and Methods
Variables of enum type expose the compiler-generated properties and any custom methods defined in the enum class:
println(current.name) // "RED"
println(current.ordinal) // 0
println(current.hex()) // "#FF0000" - custom method
// Safe comparison using == (enums are singletons)
if (current == Color.RED) {
println("Currently red")
}
The name and ordinal properties are declared in the base Enum<E> class, while hex() is specific to the Color example. Because enum entries are singleton objects, reference equality (===) and structural equality (==) yield the same result.
Iterating Over Enum Constants: values() vs entries
When you need to enumerate all constants of an enum type, Kotlin provides two main approaches with different performance characteristics.
Using values()
The values() function returns a new Array<E> containing all enum constants:
val allColors: Array<Color> = Color.values()
println(allColors.contentToString()) // [RED, GREEN, BLUE]
Important: values() creates a fresh array on every invocation. In performance-critical code or tight loops, this allocation overhead can accumulate.
Using entries (Recommended)
Introduced in Kotlin 1.9 and defined in libraries/stdlib/src/kotlin/enums/EnumEntries.kt, the entries property returns an EnumEntries<E> — an immutable list view that avoids allocation:
for (c in Color.entries) {
println("${c.ordinal}: ${c.name}")
}
The EnumEntries interface extends List<E> and provides constant-time contains and indexOf operations. For generic code, you can use the enumEntries<T>() inline function, which returns the same cached list without requiring a specific enum class reference.
When to use which:
- Use
entriesfor read-only iteration, membership checks, or when exposing enum constants as a collection - Use
values()only when you specifically need a mutableArrayinstance
Using Enum Types in Functions and Data Classes
Enum types integrate seamlessly with Kotlin's type system, making them ideal for function parameters and data class properties. The compiler can verify exhaustive when expressions when using enum variables:
data class Pixel(val color: Color, val x: Int, val y: Int)
fun draw(pixel: Pixel) {
when (pixel.color) {
Color.RED -> println("Drawing red pixel at (${pixel.x}, ${pixel.y})")
Color.GREEN -> println("Drawing green pixel")
Color.BLUE -> println("Drawing blue pixel")
}
}
Because Color is a sealed type with a fixed set of instances, the compiler knows that the when expression is exhaustive. If you add a new color constant later, the compiler will flag any incomplete when blocks as errors, preventing runtime bugs.
Key Implementation Files in the Kotlin Repository
The enum functionality described above is implemented across several key files in the JetBrains/kotlin repository:
| File | Role |
|---|---|
libraries/stdlib/src/kotlin/Enum.kt |
Defines the abstract Enum<E> base class as an expect class |
libraries/stdlib/src/kotlin/enums/EnumEntries.kt |
Declares EnumEntries<E> interface and enumEntries() intrinsic function |
plugins/kapt/kapt-compiler/testData/converter/enums.kt |
Test data showing concrete enum declarations with properties and methods |
compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/EnumClassLowering.kt |
JVM-specific IR lowering that generates values() and entries implementations |
kotlin-native/runtime/src/main/kotlin/kotlin/Enum.kt |
Native platform actual implementation of the Enum base class |
These files demonstrate how Kotlin abstracts enum behavior through expect/actual declarations while allowing platform-specific optimizations in the compiler backend.
Summary
- Enum declaration: Use
enum classto create a type with a fixed set of named constants, optionally including properties and methods as shown inplugins/kapt/kapt-compiler/testData/converter/enums.kt. - Variable declaration: Declare variables using the enum type (e.g.,
var current: Color = Color.RED) to leverage Kotlin's type-safe singleton semantics. - Standard properties: Access
nameandordinalfrom the baseEnum<E>class defined inlibraries/stdlib/src/kotlin/Enum.kt. - Efficient iteration: Prefer
entries(returningEnumEntries<E>fromlibraries/stdlib/src/kotlin/enums/EnumEntries.kt) overvalues()to avoid array allocations in performance-critical code. - Exhaustive checks: Use enum variables in
whenexpressions to enable compiler-verified exhaustive pattern matching.
Frequently Asked Questions
How do I declare a variable that can hold any enum constant in Kotlin?
Declare the variable using the enum class name as the type, followed by the specific constant assignment. For example: var status: Status = Status.ACTIVE. The type system ensures that only constants defined in that enum class can be assigned to the variable, preventing invalid states at compile time.
What is the difference between values() and entries in Kotlin enums?
The values() function returns a new Array containing all enum constants on every invocation, which allocates memory each time. The entries property, introduced in Kotlin 1.9, returns an immutable EnumEntries list that caches the constants, avoiding allocation on repeated access. Use entries for iteration and membership checks, and values() only when you specifically need a mutable array instance.
Can I add custom properties and methods to a Kotlin enum?
Yes, enum classes in Kotlin can contain constructors, properties, and methods just like regular classes. Each enum constant can pass arguments to the constructor, as shown in the Color example from plugins/kapt/kapt-compiler/testData/converter/enums.kt where RED(0xFF0000) passes an RGB value. You can also define abstract methods in the enum class and implement them individually for each constant.
How does Kotlin ensure type safety with enum variables?
Kotlin treats each enum class as a sealed type with a fixed set of singleton instances defined at compile time. The compiler generates a final class extending Enum<E> (defined in libraries/stdlib/src/kotlin/Enum.kt), ensuring that variables of that type can only reference the predefined constants. This enables exhaustive when expressions and prevents null or invalid states without runtime checks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →