baomidou/mybatis-plus · error · IllegalArgumentException

Type argument must be an enum: {}

Error message

Type argument must be an enum: {}

What it means

EnumCache.createMetadata builds the EnumMetadata (value-to-enum mappings) for a class and throws IllegalArgumentException('Type argument must be an enum: X') when the class is not java.lang.Enum. The metadata cache is only valid for enums; passing an interface, annotation, or ordinary class means value extraction (getEnumConstants, IEnum interface check) cannot proceed.

Source

Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/EnumCache.java:73

        }
        return CACHE.computeIfAbsent(enumClassType, EnumCache::createMetadata);
    }

    static Optional<String> findEnumValueFieldName(Class<?> clazz) {
        if (clazz == null || !clazz.isEnum()) {
            return Optional.empty();
        }
        String fieldName = ENUM_VALUE_FIELD_CACHE.computeIfAbsent(clazz, EnumCache::findEnumValueFieldNameOrEmpty);
        return NO_ENUM_VALUE_FIELD.equals(fieldName) ? Optional.empty() : Optional.of(fieldName);
    }

    static boolean isMpEnums(Class<?> clazz) {
        return clazz != null && clazz.isEnum() && (IEnum.class.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());
    }

    private static EnumMetadata createMetadata(Class<?> enumClassType) {
        if (!enumClassType.isEnum()) {
            throw new IllegalArgumentException("Type argument must be an enum: " + enumClassType.getName());
        }
        MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY);
        String getterName = resolveGetterName(enumClassType);
        Class<?> propertyType = ReflectionKit.resolvePrimitiveIfNecessary(metaClass.getGetterType(getterName));
        Invoker getInvoker = metaClass.getGetInvoker(getterName);
        Enum<?>[] enumConstants = (Enum<?>[]) enumClassType.getEnumConstants();
        Map<Object, Enum<?>> valueToEnum = new HashMap<>(enumConstants.length * 4 + 1);
        Map<Enum<?>, Object> enumToValue = new IdentityHashMap<>(enumConstants.length);
        for (Enum<?> enumConstant : enumConstants) {
            Object value = invokeValue(getInvoker, enumConstant);
            enumToValue.put(enumConstant, value);
            EnumUtils.putEnumValue(valueToEnum, value, enumConstant);
        }
        return new EnumMetadata(propertyType, enumConstants, Collections.unmodifiableMap(valueToEnum),
            Collections.unmodifiableMap(enumToValue), getterName);
    }

    private static String resolveGetterName(Class<?> enumClassType) {

View on GitHub (pinned to bf67d90747)

Solutions

  1. Make the mapped type an actual enum (declare it with the enum keyword) — classes merely implementing IEnum are not supported.
  2. Check the registered type handler for the field: non-enum types must not be handled by the enum type handler chain.
  3. Guard call sites with clazz.isEnum() (or EnumCache.isMpEnums(clazz)) before touching enum metadata APIs.

Example fix

// before: class implements IEnum but is not an enum -> IAE
public class Status implements IEnum<Integer> { ... }

// after: declare it as an enum
public enum Status implements IEnum<Integer> {
    OK(0), FAIL(1);
    private final int code;
    Status(int code) { this.code = code; }
    public Integer getValue() { return code; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!clazz.isEnum()) {
    throw new IllegalArgumentException(clazz + " is not an enum; enum handling requires java.lang.Enum");
}

Type guard

static boolean isMpEnum(Class<?> c) {
    return c != null && c.isEnum()
        && (IEnum.class.isAssignableFrom(c) || EnumCache.findEnumValueFieldName(c).isPresent());
}

Try / catch

try {
    EnumCache.metadata(candidate);
} catch (IllegalArgumentException e) {
    // fall back to non-enum handling instead of failing
    handleAsNonEnum(candidate);
}

Prevention

When it happens

Trigger: Cache.computeIfAbsent(enumClassType, EnumCache::createMetadata) runs with a non-enum class — e.g. code path determined a field 'is an mp enum' incorrectly, or a custom type handler invoked EnumCache lookups on a plain class. Also reachable when an enum-like class (abstract class implementing IEnum without being an enum) is routed to the enum cache.

Common situations: A class implements IEnum but is not declared as enum; the wrong type handler is registered for a field so enum machinery runs against a normal class; reflective code feeds raw Class objects into enum caching utilities.

Related errors


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/31fb5dce4229bafa. Report an issue: GitHub.