Enumeratum
A type-safe, reflection-free, powerful enumeration implementation for Scala with exhaustive pattern match warnings and helpful integrations.
Install / Use
/learn @lloydmeta/EnumeratumREADME
Enumeratum

Enumeratum is a type-safe and powerful enumeration implementation for Scala that offers exhaustive pattern match warnings,
integrations with popular Scala libraries, and idiomatic usage that won't break your IDE. It aims to be similar enough
to Scala's built in Enumeration to be easy-to-use and understand while offering more flexibility, type-safety (see this blog
post describing erasure on Scala's Enumeration), and
richer enum values without having to maintain your own collection of values.
Enumeratum has the following niceties:
- Zero dependencies
- Performant: Faster than
Enumerationin the standard library (see benchmarks) - Allows your Enum members to be full-fledged normal objects with methods, values, inheritance, etc.
ValueEnums that map to various primitive values and have compile-time uniqueness constraints.- Idiomatic: you're very clearly still writing Scala, and no funny colours in your IDE means less cognitive overhead for your team
- Simplicity; most of the complexity in this lib is in its macro, and the macro is fairly simple conceptually
- No usage of reflection at runtime. This may also help with performance but it means Enumeratum is compatible with ScalaJS and other environments where reflection is a best effort (such as Android)
- No usage of
synchronized, which may help with performance and deadlocks prevention - All magic happens at compile-time so you know right away when things go awry
- Comprehensive automated testing to make sure everything is in tip-top shape
Enumeratum is published for Scala 2.12.x, 2.13.x, 3.x as well as ScalaJS and ScalaNative.
Note that there are a couple of limitations for 3.x:
- All "immediate" parent types of enum entries need to be
sealed(reasoning here) - The
-Yretain-treesScalac option must be set when using ValueEnums
Integrations are available for:
- Play: JVM only
- Play JSON: JVM (included in Play integration but also available separately) and ScalaJS
- Circe: JVM and ScalaJS
- ReactiveMongo BSON: JVM only
- Argonaut: JVM and ScalaJS
- Json4s: JVM only
- ScalaCheck: JVM and ScalaJS
- Slick: JVM only
- Quill: JVM and ScalaJS
- sttp tapir: JVM and ScalaJS
- Scalafix
Table of Contents
- Quick start
- More examples
- ScalaJS
- Play integration
- Play JSON integration
- Circe integration
- ReactiveMongo BSON integration
- Argonaut integration
- Json4s integration
- Slick integration
- ScalaCheck
- Quill integration
- Cats integration
- Doobie integration
- Anorm integration
- Benchmarking
- Publishing
- Contributing
Quick start
SBT
In build.sbt, set the Enumeratum version in a variable (for the latest version, set val enumeratumVersion = the version you see
in the Maven badge above).
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % enumeratumVersion
)
Enumeratum has different integrations that can be added to your build à la carte. For more info, see the respective sections in the Table of Contents
Usage
Using Enumeratum is simple. Just declare your own sealed trait or class A that extends EnumEntry and implement it as case objects inside
an object that extends from Enum[A] as shown below.
import enumeratum._
sealed trait Greeting extends EnumEntry
object Greeting extends Enum[Greeting] {
/*
`findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
You use it to implement the `val values` member
*/
val values = findValues
case object Hello extends Greeting
case object GoodBye extends Greeting
case object Hi extends Greeting
case object Bye extends Greeting
}
// Object Greeting has a `withName(name: String)` method
Greeting.withName("Hello")
// => res0: Greeting = Hello
Greeting.withName("Haro")
// => java.lang.NoSuchElementException: Haro is not a member of Enum (Hello, GoodBye, Hi, Bye)
// A safer alternative would be to use `withNameOption(name: String)` method which returns an Option[Greeting]
Greeting.withNameOption("Hello")
// => res1: Option[Greeting] = Some(Hello)
Greeting.withNameOption("Haro")
// => res2: Option[Greeting] = None
// It is also possible to use strings case insensitively
Greeting.withNameInsensitive("HeLLo")
// => res3: Greeting = Hello
Greeting.withNameInsensitiveOption("HeLLo")
// => res4: Option[Greeting] = Some(Hello)
// Uppercase-only strings may also be used
Greeting.withNameUppercaseOnly("HELLO")
// => res5: Greeting = Hello
Greeting.withNameUppercaseOnlyOption("HeLLo")
// => res6: Option[Greeting] = None
// Similarly, lowercase-only strings may also be used
Greeting.withNameLowercaseOnly("hello")
// => res7: Greeting = Hello
Greeting.withNameLowercaseOnlyOption("hello")
// => res8: Option[Greeting] = Some(Hello)
Note that by default, findValues will return a Seq with the enum members listed in written-order (relevant if you want to
use the indexOf method).
Enum members found in nested objects will be included by findValues as well, and will appear in the order they are
written in the companion object, top to bottom. Note that enum members declared in traits or classes will not be
discovered by findValues. For example:
sealed trait Nesting extends EnumEntry
object Nesting extends Enum[Nesting] {
val values = findValues
case object Hello extends Nesting
object others {
case object GoodBye extends Nesting
}
case object Hi extends Nesting
class InnerClass {
case object NotFound extends Nesting
}
}
Nesting.values
// => res0: scala.collection.immutable.IndexedSeq[Nesting] = Vector(Hello, GoodBye, Hi)
For an interactive demo, checkout this Scastie snippet.
More examples
Enum
Continuing from the Greeting enum declared in the quick-start section:
import Greeting._
def tryMatching(v: Greeting): Unit = v match {
case Hello => println("Hello")
case GoodBye => println("GoodBye")
case Hi => println("Hi")
}
/**
Pattern match warning ...
<console>:24: warning: match may not be exhaustive.
It would fail on the following input: Bye
def tryMatching(v: Greeting): Unit = v match {
*/
Greeting.indexOf(Bye)
// => res2: Int = 3
The name is taken from the toString method of the particular
EnumEntry. This behavior can be changed in two ways.
Manual override of name
The first way to change the name behaviour is to manually override the def entryName: String method.
import enumeratum._
sealed abstract class State(override val entryName: String) extends EnumEntry
object State extends Enum[State] {
val values = findValues
case object Alabama extends State("AL")
case object Alaska extends State("AK")
// and so on and so forth.
}
import State._
State.withName("AL")
Mixins to override the name
The second way to override the name behaviour is to mixin the stackable traits provided for common string
conversions, Snakecase, UpperSnakecase, CapitalSnakecase, Hyphencase, UpperHyphencase, CapitalHyphencase, Dotcase, UpperDotcase, CapitalDotcase, Words, UpperWords, CapitalWords, Camelcase, LowerCamelcase, Uppercase, Lowercase, and Uncapitalised.
import enumeratum._
import enumeratum.EnumEntry._
sealed trait Greeting extends EnumEntry with Snakecase
object Greeting extends Enum[Greeting] {
val values = findValues
case object Hello extends Greeting
case object GoodBye extends Greeting
case object ShoutGoodBye extends Greeting with Uppercase
}
Greeting.withName("hello")
Greeting.withName("good_bye")
Greeting.withName("SHOUT_GOOD_BYE")
ValueEnum
Asides from enumerations that resolve members from String names, Enumeratum also supports ValueEnums, enums that resolve
members from simple values like Int, `Long
Related Skills
node-connect
340.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.1kCommit, push, and open a PR
