Last Updated: February 12, 2026
Imagine you're building an e-commerce platform and you need to track the status of every order. Orders flow through various states: placed, confirmed, shipped, delivered, or cancelled. How do you represent these states in code?
You could use strings: "PLACED", "SHIPPED", "DELIVERED". But what happens when someone types "Shiped" instead of "SHIPPED"?
The compiler won't catch it and your code will silently fail at runtime.
You could use integers: 1 for placed, 2 for shipped, 3 for delivered. But now your code is littered with magic numbers. What does if (status == 2) mean?
This is exactly the type of problem enums solve.
An enum (short for enumeration) is a special data type that defines a fixed set of named constants. Unlike strings or integers, enums are type-safe, meaning the compiler ensures you can only use values that actually exist in your defined set.
They ensure that a variable can only take one out of a predefined set of valid options.
If a value can only be one of a predefined set of options, consider using an enum.
To appreciate what enums give you, consider the alternative. Without enums, you'd represent order statuses as strings scattered throughout your codebase:
This code compiles without any warnings. The typo "PNDING" is a perfectly valid string as far as the compiler is concerned. The bug only surfaces when a customer complains that their order never gets processed.
Enums eliminate this entire category of bugs. When you define OrderStatus as an enum with values like PENDING, CONFIRMED, SHIPPED, and DELIVERED, the compiler knows exactly which values are valid.
Here are several key advantages Enums provide over plain constants or strings:
"PENDING" or 3 in your code.OrderStatus.SHIPPED is far more descriptive than 3.Enums are perfect for defining categories or states that rarely change.
PENDING, IN_PROGRESS, COMPLETED)ADMIN, CUSTOMER, DRIVER)CAR, BIKE, TRUCK)NORTH, SOUTH, EAST, WEST)By using enums instead of raw strings, you make your system easier to understand and harder to misuse.
The most basic form of an enum defines a list of named constants under a single type. Let's model the status of an order in an e-commerce system.
This enum defines a finite set of valid states an order can have. Nothing else is allowed.
Simple enums work well when you just need a list of named constants. But what if each constant needs to carry additional data?
Enums can do more than just name constants. In many languages, each enum value can hold additional data and even define behavior. This makes them surprisingly powerful for modeling domain concepts.
Let’s consider a Coin enum that represents U.S. coins and their denominations. Each coin has a name (PENNY, NICKEL, DIME, QUARTER) and a value in cents (1, 5, 10, 25). Instead of maintaining a separate lookup table for coin values, you can embed the value directly in the enum.
This is far more elegant and safe than maintaining separate arrays or lookup maps. The data lives right next to the constant it belongs to, so there's no risk of the value and the name getting out of sync.
Let's build a small order processing system that uses two enums: OrderStatus (which we've already seen) and PaymentMethod. Together, they demonstrate how enums bring structure and safety to a real domain model.
The Order class tracks an order's status, payment method, and total amount. It provides methods to advance the status through its lifecycle, cancel the order, and display order information.
The key insight is that enums control the valid transitions: an order can only move forward through the status chain (PLACED to CONFIRMED to SHIPPED to DELIVERED), and cancellation is only allowed before shipping.
advanceStatus() method enforces that orders move through a valid sequence. You can't jump from PLACED to DELIVERED or go backwards from SHIPPED to CONFIRMED. The enum combined with the switch statement makes the valid transitions explicit.PaymentMethod carries its own fee percentage. There's no separate lookup table or configuration file to keep in sync. Adding a new payment method means adding one enum value with its fee, and the rest of the code works automatically.cancel() method uses enum comparison to enforce business rules. You can only cancel before shipping. If someone tries to cancel a shipped order, the method returns false. No ambiguity, no string matching.RETURNED status? Add it to the enum and update the switch statement. The compiler will remind you if you miss handling it. Need a new payment method like WALLET? Add one line to the enum with its display name and fee.