Kotlin Help

Enum classes

Enum classes represent a fixed set of possible values. Use an enum class when a value can only be one of several predefined options, such as available states or modes.

Each value in an enum class is called an enum constant. Enum constants behave like singleton objects of the enum class type, so they can have properties, functions, and custom behavior.

Enum classes are the best fit when all possible values are known in advance and have the same structure. If you need to hold different data or have a different structure for each case, use sealed classes or interfaces.

Declare enum classes

To create an enum class, use the enum keyword and follow the usual class syntax with a body enclosed in curly braces. Inside the class body, list the enum constants separated by commas:

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

In this example, Direction is the enum class, and NORTH, SOUTH, WEST, and EAST are enum constants.

By convention, enum constants are usually written in uppercase because they represent constant values.

You can access an enum constant by using the enum class name followed by the constant name:

enum class Direction { NORTH, SOUTH, WEST, EAST } fun main() { // `Direction.NORTH` is an enum constant of type `Direction`. val direction: Direction = Direction.NORTH println(direction) // NORTH }

Every enum class in Kotlin inherits from the Enum<T> base class, where T is the enum class itself. For example, the Direction enum class inherits from Enum<Direction>. This is why enum constants have built-in properties, such as name and ordinal.

Working with enum constants

Since enum constants are values, you can assign them to variables, print them, pass them to functions, compare them, and use them in when expressions.

Declare enum constants

To declare enum constants, first define properties in the enum class constructor and then pass values to each enum constant in parentheses. Unlike some other languages, Kotlin doesn't use assignment syntax, for example RED = "#FF0000".

Enum constants can have associated values of any type. Strings and numbers are common examples, but you can also use other types, such as Boolean, another enum class, or a custom class.

Consider the Color enum class that stores a hexadecimal color code for each color:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") }

The value passed to each enum constant must match the constructor parameter type. Here, hex is a string property of the Color enum class. Each enum constant passes its own string value for this property.

You can also associate numeric values with enum constants. For example, declare the Int type in the constructor and provide an Int value for each enum constant:

enum class Priority(val level: Int) { LOW(0), MEDIUM(1), HIGH(2) }

Access enum constants and their properties

You can access an enum constant through the enum class name. To access a property associated with an enum constant, use the dot notation, such as color.hex or Color.GREEN.hex:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } fun main() { val color: Color = Color.RED println(color) // RED println(color.hex) // #FF0000 println(Color.GREEN.hex) // #00FF00 }

Here, Color.RED is an enum constant of the Color type. The color variable stores this enum constant.

Besides any properties you define, every enum constant also has the built-in name and ordinal properties for getting its name and position (starting from 0) in the enum class declaration:

enum class RGB { RED, GREEN, BLUE } fun main() { println(RGB.RED.name) // RED println(RGB.RED.ordinal) // 0 }

Pass enum constants to functions

Because enum constants are values, you can pass them to functions. This way, a function accepts only the fixed set of options defined in the enum class, ensuring type-safe code:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun printColor(color: Color) { println("Color: $color") println("Hex code: ${color.hex}") } fun main() { printColor(Color.BLUE) // Color: BLUE // Hex code: #0000FF } //sampleEnd

Here, the printColor() function accepts a value of type Color, so you can pass any Color enum constant to it.

Although enum constants behave like singleton objects, the compiler treats them as values of the enum class type. You can use the enum class name itself as a type, but you can't use enum constants as enum types:

enum class Color { RED, GREEN, BLUE } fun printColor(color: Color) { println(color) } fun printRed(color: Color.RED) { println(color) // Error: enum entry cannot be used as a type }

Use enum constants in when expressions

Enum classes work best with when expressions when you want to handle each constant separately:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun describeColor(color: Color): String { return when (color) { Color.RED -> "Red is a warm color" Color.GREEN -> "Green is a natural color" Color.BLUE -> "Blue is a cool color" } } fun main() { println(describeColor(Color.RED)) // Red is a warm color } //sampleEnd

When you use all enum constants in a when expression, you don't need an else branch.

Find enum constants

Sometimes you need to get an enum constant from a string, an index, or one of its associated values. Kotlin provides built-in APIs to look up constants by name, position, or custom values.

For example, consider an enum class where each color has an associated RGB value. To find an enum constant by its name, use the valueOf() function:

enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } fun main() { val color = Color.valueOf("RED") println(color) // RED }

The name passed to valueOf() must match the enum constant name exactly. If there is no enum constant with the specified name, valueOf() throws an IllegalArgumentException.

To find an enum constant by its position in the enum declaration, use the getOrNull() function on the enum's entries property:

enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } //sampleStart fun main() { val color = Color.entries.getOrNull(0) println(color) // RED } //sampleEnd

Enum positions start from 0. In this example, RED has the position 0, GREEN is at 1, and BLUE is at 2.

This is useful when you have an integer, for example from a file or user input, that represents an enum constant position. Unlike some other languages, Kotlin doesn't let you cast an Int directly to an enum constant. Instead, use the integer as an index and look up the constant with entries.getOrNull(index).

If the integer represents a value that should remain stable even if you reorder the enum constants, define an explicit numeric property, for example, rgb or code and search for the constant with the matching value.

Since entries is a specialized List, you can use standard collection APIs with it. For example, to find an enum constant by an associated value, search through entries using first():

enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } //sampleStart fun main() { val color = Color.entries.first { it.rgb == 0xFF0000 } println(color) // RED } //sampleEnd

The first() function throws a NoSuchElementException if no matching constant is found. To get null instead, use firstOrNull().

To get the number of enum constants, use the size property. For example:

enum class RGB { RED, GREEN, BLUE } fun main() { println(RGB.entries) // [RED, GREEN, BLUE] println(RGB.entries.size) // 3 println("The first color is: ${RGB.valueOf("RED")}") // "The first color is: RED" }

If you often need to look up enum constants by name, position, or associated value, add helper functions in a companion object:

enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF); companion object { fun fromName(name: String): Color? = entries.find { it.name == name } fun fromPosition(position: Int): Color? = entries.getOrNull(position) fun fromRgb(rgb: Int): Color? = entries.find { it.rgb == rgb } } } fun main() { println(Color.fromName("RED")) // RED println(Color.fromPosition(1)) // GREEN println(Color.fromRgb(0x0000FF)) // BLUE println(Color.fromRgb(0xABCDEF)) // null }

Companion object helper functions are useful when you want safe lookups that return null instead of throwing an exception.

The lookup APIs used above, such as entries and valueOf(), are examples of synthetic members. In this context, synthetic means that Kotlin provides these members automatically, even though you don't declare them yourself. This is why every enum class can list its constants with the entries property and get a constant by name with the valueOf() function without the need to write extra code.

You can access the constants in an enum class using generic helper functions such as enumEntries<T>() and enumValueOf<T>(). These functions use reified type parameters. Such parameters keep the actual enum type available inside a generic inline function, so the helper functions can work with the enum type T directly:

Function

Description

enumEntries<T>()

(Recommended) Returns all enum entries of the enum type T. Every call returns the same list.

enumValues<T>()

Returns an array with all enum entries of the enum type T. Every call enumValues<T>() creates a new array.

enumValueOf<T>()

Returns a single enum entry by its name, throwing an IllegalArgumentException if no enum entry matches.

For example:

import kotlin.enums.enumEntries enum class RGB { RED, GREEN, BLUE } inline fun <reified T : Enum<T>> printAllValues() { println(enumEntries<T>().joinToString { it.name }) } inline fun <reified T : Enum<T>> findByName(name: String): T = enumValueOf<T>(name) fun main() { printAllValues<RGB>() // RED, GREEN, BLUE println(findByName<RGB>("GREEN")) // GREEN }

For more information about inline functions and reified type parameters, see Inline functions.

Compare and sort enum constants

Use the == structural equality operator to compare enum constants:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun main() { val color = Color.RED println(color == Color.RED) // true println(color == Color.BLUE) // false } //sampleEnd

Since each enum constant behaves like a singleton object, comparing enum constants checks whether both values refer to the same constant.

All enum classes implement the Comparable interface by default, so you can compare and sort enum constants. Constants are ordered by their position in the enum declaration (their ordinal value), which means the constant declared first is considered the smallest:

enum class Priority { LOW, MEDIUM, HIGH } fun main() { println(Priority.LOW < Priority.HIGH) // true println(Priority.HIGH > Priority.MEDIUM) // true }

Sorting follows the same declaration order. For example, entries.sorted() returns the constants in the order in which they are declared, regardless of their names:

enum class Priority { HIGH, LOW, MEDIUM } fun main() { println(Priority.entries.sorted()) // [HIGH, LOW, MEDIUM] }

The Enum<T> class provides the compareTo(), equals(), and hashCode() functions, and you can't override them to customize their behavior like in normal classes. Comparison always follows the declaration order.

If you need a different order, don't rely on the declaration order. Instead, define an explicit property and sort by it. For example, sort colors by their brightness:

enum class Color(val brightness: Int) { RED(1), GREEN(3), BLUE(2) } fun main() { println(Color.entries.sortedBy { it.brightness }) // [RED, BLUE, GREEN] }

For more information, see Ordering.

Add functions to enum classes

Just like properties, enum classes can have functions. You can add functions that are shared by all enum constants, combine them with properties, or define operator functions.

Add functions shared by all constants

To add behavior that every enum constant shares, define a function in the enum class body. If the enum class defines any members, separate the constant definitions from the member definitions with a semicolon:

enum class Direction { NORTH, SOUTH, WEST, EAST; fun isVertical(): Boolean = this == NORTH || this == SOUTH } fun main() { println(Direction.NORTH.isVertical()) // true println(Direction.EAST.isVertical()) // false }

Every enum constant can call the shared function. Inside the function, this refers to the enum constant it's called on.

You can combine constructor properties with functions to associate data with each constant and add behavior that uses that data:

enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF"); fun describe(): String = "$name has hex code $hex" } fun main() { println(Color.RED.describe()) // RED has hex code #FF0000 }

Here, each constant stores its own hex value, and the shared describe() function uses both the built-in name property and the hex property.

Add operator functions

Enum classes can also define operator functions, so you can use enum constants with operators. For example, define the not() operator function to return the opposite direction with the ! operator:

enum class Direction { NORTH, SOUTH, WEST, EAST; operator fun not(): Direction = when (this) { NORTH -> SOUTH SOUTH -> NORTH WEST -> EAST EAST -> WEST } } fun main() { println(!Direction.NORTH) // SOUTH }

Use anonymous classes

Enum constants can declare their own anonymous classes with their corresponding functions, as well as with overriding base functions. With anonymous classes, you write the class body directly after the enum constant name and Kotlin infers the enum class as the supertype.

This is useful when you declare an abstract function in the enum class and require each constant to provide its own implementation. Each constant overrides the abstract function inside its own anonymous class:

enum class ProtocolState { WAITING { override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState } fun main() { var state = ProtocolState.WAITING println(state) // WAITING state = state.signal() println(state) // TALKING }

Here, each constant implements the abstract signal() function differently, so calling signal() returns a different next state depending on the constant.

Although enum constants behave like singleton objects, the type of an enum constant is the enum class itself, not its own anonymous class. That's why you can't access members declared inside the body of an anonymous class:

enum class ProtocolState { WAITING { val waitingMessage = "Waiting for a signal" override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState } fun main() { println(ProtocolState.WAITING.waitingMessage) // Error: unresolved reference 'waitingMessage' }

To expose data or behavior for every constant, declare it in the enum class body, using an abstract member when each constant needs its own implementation.

Implement interfaces in enum classes

An enum class can implement an interface, but it cannot inherit from a class. You can provide a common implementation of the interface members for all enum constants or let each constant provide its own implementation in an anonymous class.

To implement an interface, add it to the enum class declaration:

import java.util.function.BinaryOperator import java.util.function.IntBinaryOperator //sampleStart enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator { PLUS { override fun apply(t: Int, u: Int): Int = t + u }, TIMES { override fun apply(t: Int, u: Int): Int = t * u }; override fun applyAsInt(t: Int, u: Int) = apply(t, u) } //sampleEnd fun main() { val a = 13 val b = 31 for (f in IntArithmetics.entries) { println("$f($a, $b) = ${f.apply(a, b)}") } }

In this example, the IntArithmetics enum class implements two interfaces in the enum class declaration: BinaryOperator<Int> and IntBinaryOperator. Each constant can override interface members inside its own anonymous class body, as PLUS and TIMES do for apply(), while applyAsInt() provides a shared implementation for all constants.

08 September 2026