Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

You can declare an enum inside a Java class. The precise term is a nested enum, not an inner class: member enums are implicitly static, so they do not need an instance of the enclosing class and cannot implicitly access its instance fields.

Declare and use a member enum

Put the enum declaration inside the class whose API or implementation it belongs to. Outside that class, refer to it through the enclosing type:

public final class Order {
    public enum Status {
        NEW,
        PAID,
        SHIPPED,
        CANCELLED
    }

    private Status status = Status.NEW;

    public Status status() {
        return status;
    }

    public void markPaid() {
        status = Status.PAID;
    }
}

Order order = new Order();
Order.Status current = order.status();

if (current == Order.Status.NEW) {
    order.markPaid();
}

Inside Order, Status.NEW is enough. Code outside the class normally writes Order.Status.NEW. You can also import the nested type with import com.example.Order.Status; and then use Status.PAID. A static import such as import static com.example.Order.Status.PAID; is legal, but can make the enum’s ownership less apparent.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A minimal standalone example can be saved as Order.java, then compiled and run with javac Order.java and java Order. If the main method assigns Order.Status.PAID and prints it, the output is PAID. For reproducible builds, set the project’s intended Java release rather than relying on the installed JDK; for example, javac --release 17 Order.java.

Nested enum versus inner class

Java uses inner class for a non-static nested class. An enum declared as a member of another class is different: it is implicitly static and is therefore a nested type, not an inner class. The distinction affects whether the nested type has an enclosing object.

class Outer {
    private int value = 42;

    class Inner {
        int readValue() {
            return value;
        }
    }

    enum Kind {
        A
    }
}

Inner can read the particular Outer instance’s value. Kind has no such implicit connection. It can be used without constructing an Outer object:

Outer.Kind kind = Outer.Kind.A;

You cannot construct an enum instance with new; enum constants are the instances:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
new Outer.Kind(); // Does not compile

Adding static to a member enum is allowed but redundant:

class Response {
    enum Code { OK, NOT_FOUND }
}

// Equivalent declaration:
class ResponseWithExplicitModifier {
    static enum Code { OK, NOT_FOUND }
}

Here, static means the nested type does not require an enclosing instance. It does not turn enum constants into ordinary mutable static fields. These language rules are specified in the Java Language Specification, Chapter 8.

Choose visibility and placement deliberately

A member enum follows member access rules. Its accessibility is also bounded by the accessibility of its enclosing class.

  • public: accessible wherever the enclosing class is accessible.
  • protected: accessible under Java’s protected-member rules.
  • private: accessible only within the enclosing top-level class.
  • No modifier: package-private.

A private nested enum can keep implementation choices out of a class’s public API. A public nested enum is part of that API: clients may compile against it, so renaming the enclosing type, moving the enum, or changing its constants can affect them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a nested enum when the type belongs conceptually to one abstraction and the enclosing class is a useful namespace, as in Payment.Status or HttpRequest.Method. Choose a top-level enum if unrelated classes use it or it has an independent identity, such as a package-level PaymentStatus. A local enum, covered below, fits a finite set used only in one method or block.

Add fields, constructors, methods, and interfaces

Enum constants come first. If the enum declares fields, constructors, methods, or other members after its constants, terminate the constant list with a semicolon.

public final class FileEntry {
    public enum Kind {
        FILE("file"),
        DIRECTORY("directory"),
        SYMBOLIC_LINK("symlink");

        private final String label;

        Kind(String label) {
            this.label = label;
        }

        public String label() {
            return label;
        }
    }
}

Use FileEntry.Kind.DIRECTORY.label() to retrieve the label. Application code cannot call the enum constructor; the runtime creates the declared constants. An enum cannot extend an arbitrary class because every enum already extends java.lang.Enum, but it can implement interfaces. See Oracle’s enum tutorial for the declaration rules.

For example, a nested enum can implement an interface declared alongside it:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
public final class Payment {
    public interface Displayable {
        String displayName();
    }

    public enum Status implements Displayable {
        PENDING("Pending"),
        PAID("Paid"),
        FAILED("Failed");

        private final String label;

        Status(String label) {
            this.label = label;
        }

        @Override
        public String displayName() {
            return label;
        }
    }
}

Use a constant-specific class body when each constant genuinely supplies its own polymorphic implementation:

enum Operation {
    ADD {
        @Override
        int apply(int left, int right) {
            return left + right;
        }
    },
    MULTIPLY {
        @Override
        int apply(int left, int right) {
            return left * right;
        }
    };

    abstract int apply(int left, int right);
}

For short behavior, a single method with a switch over the constants is often simpler. Choose the constant-specific form when keeping behavior with each constant improves the design, rather than merely to avoid a small switch.

Use enum methods without treating them as stable identifiers

Enum types provide compiler-generated methods such as values() and valueOf(String), in addition to methods inherited from Enum.

  • values() returns the constants in declaration order.
  • valueOf("PAID") looks up an exact, case-sensitive constant name; an unknown name causes an exception.
  • name() returns the declared identifier exactly.
  • toString() can be overridden, so do not assume it always equals name().
  • ordinal() is the zero-based declaration position.

For example, Order.Status.values() lists every status, while Order.Status.valueOf("PAID") returns the PAID constant. The Java 21 Enum API documentation specifies these methods and their behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not use ordinal() as a database key, business code, or persisted representation: inserting or reordering constants changes the position. Give a constant an explicit value instead:

enum Priority {
    LOW(10),
    MEDIUM(20),
    HIGH(30);

    private final int code;

    Priority(int code) {
        this.code = code;
    }

    public int code() {
        return code;
    }
}

Likewise, use name() when you specifically need the declared Java identifier; use an explicit field when a value must remain stable for an external API, file, or database.

Parse external text with an explicit policy

Calling valueOf(input) directly is suitable only when input is already guaranteed to match a constant name exactly. If input comes from a user or external system, decide how to handle case, surrounding whitespace, aliases, and unknown values. One simple case-insensitive parser is:

enum Status {
    NEW,
    PAID,
    SHIPPED;

    static Optional<Status> parse(String text) {
        if (text == null) {
            return Optional.empty();
        }

        for (Status status : values()) {
            if (status.name().equalsIgnoreCase(text.trim())) {
                return Optional.of(status);
            }
        }

        return Optional.empty();
    }
}

For repeated lookups in a large enum, a map can be built once, using a defined normalization rule such as Locale.ROOT. If the external representation must survive renaming Java constants, give each constant an explicit external code instead of treating its name as a contract.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Switch on enum constants

A traditional switch statement uses the constants by their unqualified names in the case labels:

switch (order.status()) {
    case NEW:
        startPayment();
        break;
    case PAID:
        shipOrder();
        break;
    case SHIPPED:
        notifyCustomer();
        break;
    case CANCELLED:
        cancelFulfillment();
        break;
}

On Java 14 and later, switch expressions can produce a value; this example uses arrow labels:

String message = switch (order.status()) {
    case NEW -> "Awaiting payment";
    case PAID -> "Ready to ship";
    case SHIPPED -> "In transit";
    case CANCELLED -> "Cancelled";
};

A switch expression over a known enum can be exhaustive without a default. That lets the compiler flag code that needs attention when a constant is added. A default branch can be appropriate when a component must defensively handle enum evolution from another module, but it can also conceal an unhandled new case. Choose based on whether compile-time pressure or runtime fallback is the safer behavior for the application.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Declare a local enum when the type is truly local

Java 16 and later allow a local enum declaration inside a method or block:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
class Lexer {
    void scan(String input) {
        enum TokenType {
            WORD,
            NUMBER,
            SYMBOL
        }

        TokenType type = TokenType.WORD;
        System.out.println(type);
    }
}

The type is visible only in its enclosing block and, like other nested enums, does not capture a local variable or enclosing instance. Do not write static enum for a local enum; the explicit modifier is not permitted. Code compiled for Java 15 or earlier cannot use local enums. Java 16’s changes are described in JEP 395.

To check installed versions, run java --version and javac --version. To compile a local-enum example using Java 16 language features, use an appropriate release target, for example javac --release 16 Lexer.java. If other methods or tests need to name the type, make it a member enum instead.

Enums inside inner classes and older Java versions

An enum may be declared inside an inner class in modern Java:

class Outer {
    class Inner {
        enum State {
            ACTIVE,
            INACTIVE
        }
    }
}

Outer.Inner.State state = Outer.Inner.State.ACTIVE;

This is a version-sensitive case. Older Java rules prohibited static members in inner classes, which also excluded implicitly static member enums. Java 16 relaxed those restrictions; current language rules allow the declaration. The enum still does not capture an Inner instance or gain implicit access to its instance fields. For the historical change, see the Java 16 preview specification; for the current rules, see the current Java Language Specification. If supporting older source levels, avoid this form.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reflection, binary names, and serialization

In source code, use a nested type’s canonical name, such as com.example.Outer.Status. Its binary name commonly uses a dollar sign, such as com.example.Outer$Status. Ordinary Java code should refer to it as Outer.Status; avoid hard-coding binary names unless working with reflection, class loading, or bytecode tools.

When a constant has a constant-specific class body, constant.getClass() may identify a generated subclass rather than the enum declaration itself. Use constant.getDeclaringClass() when you need the enum type that declared the constant.

Java enum serialization has special rules: a constant’s serialized identity is based on its name, and enum serialization cannot be customized in the same way as ordinary serializable classes. Renaming or removing a constant can therefore affect previously serialized data. For durable database or wire formats, use an explicit code and define how unknown values are handled.

Common compile-time and design mistakes

  • Trying to instantiate a constant: new Order.Status() is invalid. Refer to a declared value such as Order.Status.PAID.
  • Reading an enclosing instance field: a nested enum has no implicit enclosing object. Pass the enclosing object as an argument if that dependency is intentional, or reconsider where the behavior belongs.
  • Writing static on a local enum: declare the enum directly in the block without that modifier.
  • Omitting the semicolon before members: use PAID; before declaring fields or methods after the constants.
  • Passing differently cased input to valueOf: valueOf("paid") does not match PAID; normalize or parse deliberately.
  • Persisting ordinals or assuming toString() is fixed: use explicit codes for stable external representations.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.