This document provides comprehensive guidance for AI agents (Claude, GitHub Copilot, etc.) working on the Enumeratum codebase.
Enumeratum is a type-safe enumeration library for Scala that provides:
- Exhaustive pattern matching with compiler warnings
- 4x faster performance than stdlib Enumeration
- Zero dependencies in core
- Full ScalaJS, ScalaNative, and JVM support
- Rich integrations with popular Scala libraries
Current Version: 1.9.4-SNAPSHOT (stable: 1.9.3)
License: MIT
Scala Versions: 2.12.21, 2.13.18, 3.3.7
Main Branch: master
enumeratum/
├── macros/ # Compile-time value discovery (core dependency)
├── enumeratum-core/ # Base Enum and ValueEnum traits
├── enumeratum-test/ # Shared test models
└── enumeratum-{integration}/ # Library integrations (play, circe, cats, etc.)
-
Macros Layer (
/macros)- Compile-time discovery of enum values via
findValues - Scala 2: Uses
scala.reflect.macros - Scala 3: Uses
scala.quotedAPI - Version-specific:
/src/main/scala-2/and/src/main/scala-3/
- Compile-time discovery of enum values via
-
Core Layer (
/enumeratum-core)EnumEntry: Base trait withentryNameEnum[A]: String-based lookup (withName, indexOf)ValueEnum[ValueType, EntryType]: Value-based lookup (withValue)- Specialized: IntEnum, LongEnum, ShortEnum, ByteEnum, CharEnum, StringEnum
-
Integration Layer (various modules)
- JSON: play-json, circe, argonaut, json4s
- Web: play (bindables, forms)
- Database: slick, quill, doobie, reactivemongo
- Typeclasses: cats, scalacheck
Most modules use crossProject(JSPlatform, JVMPlatform, NativePlatform) with CrossType.Pure:
- JVM/JS/Native share identical source code
- No platform-specific code in most modules
- Exceptions: Play (JVM only), some integrations (JVM+JS only)
Formatter: Scalafmt 3.8.6 (config: .scalafmt.conf)
sbt scalafmtAll scalafmtSbtSettings:
- Max column: 100
- Style: defaultWithAlign
- Dialect: Scala 2.13 syntax targeting Scala 3 (Scala213Source3)
Always: -Xfatal-warnings (all warnings are errors)
Scala 2 Key Flags:
-language:higherKinds,-language:implicitConversions-Ywarn-dead-code,-Ywarn-value-discard-Xlint
Scala 3 Key Flags:
-Yretain-trees(REQUIRED for ValueEnums to work)
Projects:
- Main modules:
enumeratum-{feature}(e.g.,enumeratum-circe) - Aggregates:
{feature}-aggregate(e.g.,circe-aggregate) - Cross-projects auto-suffixed:
coreJVM,coreJS,coreNative
Packages:
- Main:
enumeratum - Values:
enumeratum.values
Traits:
- Base:
Enum[A],ValueEnum[V, E] - Entries:
EnumEntry,IntEnumEntry, etc. - Integrations: Library-prefixed (e.g.,
PlayEnum,CirceEnum)
Source Layout:
/src/main/scala/ # Common code (all versions)
/src/main/scala-2/ # Scala 2.x only
/src/main/scala-3/ # Scala 3.x only
/compat/src/main/scala-2.12/ # Scala 2.12 specific
/compat/src/main/scala-2.13/ # Scala 2.13+ specific
Pattern: Isolate version-specific code in separate directories rather than using version checks.
sealed trait MyEnum extends EnumEntry
object MyEnum extends Enum[MyEnum] {
val values = findValues // Macro discovers case objects at compile-time
case object Value1 extends MyEnum
case object Value2 extends MyEnum
}sealed abstract class MyEnum(val value: Int) extends IntEnumEntry
object MyEnum extends IntEnum[MyEnum] {
val values = findValues // Validates uniqueness at compile-time
case object Value1 extends MyEnum(1)
case object Value2 extends MyEnum(2)
}Stackable traits for automatic name transformation:
sealed trait Color extends EnumEntry with Snakecase
// or: Uppercase, Lowercase, UpperSnakecase, Hyphencase, etc.Important: All transformations cached in lazy vals for performance.
- Throwing:
withName,withValue - Option:
withNameOption,withValueOpt - Either:
withNameEither,withValueEither(returnsNoSuchMember[A])
/build.sbt- Main build (898 lines)/project/plugins.sbt- SBT plugins/project/Versions.scala- Version management/project/CoreJVMTest.scala- Generated test logic
# Test specific version
sbt "++2.13.18 test"
# Test all versions
sbt "+test"
# Compile for all platforms
sbt "coreJVM/test" "coreJS/test" "coreNative/test"To test with local macro changes (important when modifying macros):
sbt -Denumeratum.useLocalVersion "++2.13.18 test"This is set in CI via SBT_OPTS.
Per-Module:
sbt "project circe-aggregate" +clean +publishSignedAll Modules:
sbt +publishSigned- ScalaTest 3.2.19 with
AnyFunSpecandMatchers - ScalaCheck 1.18.0 for property testing
Core Tests:
- Manual:
/enumeratum-core/src/test/scala/enumeratum/ - Generated:
/enumeratum-core-jvm-tests/(100 random enums via macro)
Integration Tests:
- Each module has
/src/test/directory - Uses shared models from
/enumeratum-test/
Version-Specific Tests:
/src/test/scala-2/- Scala 2 only/src/test/scala-3/- Scala 3 only/compat/src/test/scala-2.13/, etc.
# All tests for a version
sbt "++2.13.18 test"
# Specific module
sbt "circe/test"
# With coverage (Scala 2.13 only)
sbt coverage "++2.13.18 test" coverageReport coverageAggregate
# Cross-platform
sbt "coreJVM/test" "coreJS/test" "coreNative/test"- Tool: Scoverage (only on JVM, Scala 2.13)
- Exclusions: Macros and internal utilities
coverageExcludedPackages := """enumeratum\.EnumMacros;enumeratum\.ContextUtils;enumeratum\.ValueEnumMacros"""
File: .github/workflows/ci.yml
Matrix:
- Java 11
- Scala: 2.12.21, 2.13.18, 3.3.7
Environment:
SCALAJS_TEST_OPT: full # Full optimization for JS tests
SBT_OPTS: -Denumeratum.useLocalVersion # Test with local macros- Checkout
- Setup Scala + Java 11
- Cache Coursier dependencies
- For Scala 2.13.18:
- Format check:
scalafmtCheck,scalafmtSbtCheck - Compile:
test:compile,test:doc - Coverage:
coverage,test,coverageReport,coverageAggregate - Upload to Codecov
- Format check:
- For other versions:
- Compile:
test:compile,test:doc - Test:
test
- Compile:
When modifying /macros/, ALWAYS test with:
sbt -Denumeratum.useLocalVersion testWithout this flag, tests may use published macro artifacts instead of your changes.
ValueEnums break without this flag. It's already in build.sbt for Scala 3, but important when adding new modules.
When modifying core traits:
- Check both
/src/main/scala-2/AND/src/main/scala-3/ - Update macro implementations in both versions
- Test with
sbt "+test"for all versions
JSON4S integration is disabled on Scala 3 due to upstream compatibility issues. Don't try to fix without checking json4s status.
withNameandwithValueare hot paths- All lookups use pre-built maps (lazy vals)
- Name transformations cached in lazy vals
- Never add synchronization (unlike stdlib Enumeration)
ValueEnums enforce unique values at compile-time via macros. Changes to value validation must work in both Scala 2 and 3 macro implementations.
Most projects use CrossType.Pure meaning JVM/JS/Native share identical source. Platform-specific code must go in separate projects or compat layers.
-
Create crossproject:
lazy val newIntegration = crossProject(JSPlatform, JVMPlatform, NativePlatform) .crossType(CrossType.Pure) .in(file("enumeratum-new-integration")) .dependsOn(core)
-
Add to integrationProjectRefs in build.sbt
-
Create aggregate:
lazy val `new-integration-aggregate` = aggregateProject("new-integration", newIntegrationJVM, newIntegrationJS)
-
Implement integration trait:
package enumeratum trait NewIntegrationEnum[A <: EnumEntry] { this: Enum[A] => // Integration-specific functionality }
-
Add tests using models from
enumeratum-test -
Update README.md with usage examples
-
Test all versions:
sbt "project new-integration-aggregate" +test
-
Read existing code:
# Core enum trait /enumeratum-core/src/main/scala/enumeratum/Enum.scala # Value enum trait /enumeratum-core/src/main/scala/enumeratum/values/ValueEnum.scala
-
Check version-specific code:
/enumeratum-core/src/main/scala-2/ /enumeratum-core/src/main/scala-3/
-
Update both macro implementations:
/macros/src/main/scala-2/enumeratum/EnumMacros.scala /macros/src/main/scala-3/enumeratum/EnumMacros.scala
-
Test thoroughly:
sbt -Denumeratum.useLocalVersion "+test"
- Reproduce with a test case
- Identify which layer: macros, core, or integration
- Check version-specific code if behavior differs across Scala versions
- Fix in all relevant places (Scala 2 and 3 if needed)
- Test across all versions:
sbt "+test" - Check coverage (2.13):
sbt coverage "++2.13.18 test" coverageReport - Format:
sbt scalafmtAll
-
Benchmark first:
sbt "+benchmarking/'jmh:run -i 10 -wi 10 -f3 -t 1 YourBenchmark'" -
Check hot paths:
withName,withValue: O(1) map lookupsvalues: Already pre-computed- Name transformations: Cached in lazy vals
-
Compare with stdlib: See
/benchmarking/for JMH benchmark setup
- Base enum trait:
/enumeratum-core/src/main/scala/enumeratum/Enum.scala - Base entry trait:
/enumeratum-core/src/main/scala/enumeratum/EnumEntry.scala - Value enum trait:
/enumeratum-core/src/main/scala/enumeratum/values/ValueEnum.scala - Value entry traits:
/enumeratum-core/src/main/scala/enumeratum/values/ValueEnumEntry.scala
- Scala 2 enum macros:
/macros/src/main/scala-2/enumeratum/EnumMacros.scala - Scala 3 enum macros:
/macros/src/main/scala-3/enumeratum/EnumMacros.scala - Scala 2 value macros:
/macros/src/main/scala-2/enumeratum/ValueEnumMacros.scala - Scala 3 value macros:
/macros/src/main/scala-3/enumeratum/ValueEnumMacros.scala
- Core enum tests:
/enumeratum-core/src/test/scala/enumeratum/EnumSpec.scala - Value enum tests:
/enumeratum-core/src/test/scala/enumeratum/values/ValueEnumSpec.scala - Test models:
/enumeratum-test/src/main/scala/ - Generated tests:
/enumeratum-core-jvm-tests/
- Build:
/build.sbt - Formatter:
/.scalafmt.conf - CI:
/.github/workflows/ci.yml - Plugins:
/project/plugins.sbt
- No Dependencies: Core has zero external dependencies
- No Reflection: All discovery at compile-time via macros
- Type Safety: Exhaustive pattern matching, compile-time validation
- Performance: Pre-computed maps, lazy vals, no synchronization
- Cross-Platform: Pure source sharing across JVM/JS/Native
- Integration Friendly: Mix-in traits for library-specific functionality
- Backward Compatible: Careful version management, deprecation warnings
A: Macro APIs are completely different. Scala 2 uses reflection API, Scala 3 uses quotes API.
A: Avoids initialization order issues. Enums can be used before companion object fully initialized.
A: Zero dependencies principle. All integrations are optional, separate modules.
A: Yes, follow pattern in /enumeratum-core/src/main/scala/enumeratum/values/. Ensure compile-time uniqueness validation in macros.
A: SBT crossProject plugin. Most modules use CrossType.Pure (shared source). Version-specific code in /scala-2/ and /scala-3/ directories.
A: Scoverage has best support for 2.13. Coverage on JS/Native is unreliable.
- Repository: https://github.com/lloydmeta/enumeratum
- README: Comprehensive user guide with all examples
- Issues: GitHub Issues for bug reports and feature requests
- License: MIT
Last Updated: 2026-02-01 (for version 1.9.4-SNAPSHOT)