FasterXML/jackson-databind · error · IllegalArgumentException
Cannot construct EnumMap; generic (key) type not available
Error message
Cannot construct EnumMap; generic (key) type not available
What it means
Thrown by BasicDeserializerFactory when constructing an EnumMap (or a Map<Enum,X> specialized to EnumMap) and the enum key type is not resolvable at runtime (keyType.isEnumImplType() is false). EnumMap requires a concrete enum class to be instantiated; without generic type information Jackson cannot supply it.
Solutions
- Provide a fully parameterized type using TypeReference (e.g. new TypeReference<EnumMap<MyEnum,String>>(){}) or constructType with the enum class, so the enum key is reifiable.
- Declare the target field/parameter with explicit generic key type (EnumMap<MyEnum, V>), not raw EnumMap.
- If the key type is dynamic, build a JavaType via TypeFactory.constructMapType(EnumMap.class, TypeFactory.constructType(enumClass), valueType).
Example fix
// before: raw type, key enum lost
EnumMap map = mapper.readValue(json, EnumMap.class);
// after: fully parameterized
EnumMap<MyEnum,String> map = mapper.readValue(
json, new TypeReference<EnumMap<MyEnum,String>>(){}); Defensive patterns
Strategy: validation
Validate before calling
JavaType type = mapper.getTypeFactory().constructType(new TypeReference<EnumMap<MyEnum,String>>(){});
if (!type.getKeyType().isEnumImplType()) {
throw new IllegalStateException("EnumMap key type not an enum: " + type.getKeyType());
}
mapper.readValue(json, type); Type guard
boolean hasEnumKey(JavaType t) {
return t.isMapLikeType() && t.getKeyType().isEnumImplType();
} Prevention
- Always parameterize EnumMap fields/parameters with a concrete enum key.
- Use TypeReference or constructMapType to supply erased generics.
- Avoid raw EnumMap or Map.class targets for enum-keyed maps.
When it happens
Trigger: Deserializing into a raw EnumMap, an EnumMap field whose generic key type is erased/bound to a non-enum type, or a Map<K,V> where K is an enum type variable that cannot be reified. Also when type erasure or a TypeFactory miscalculation leaves the key type as a placeholder.
Common situations: Using a raw EnumMap field/parameter without generics; deserializing into a generic type whose enum key is supplied via a TypeVariable that never gets bound; subclassing EnumMap without preserving generics; converting from Object.class or Map.class into EnumMap.
Related errors
- Unsuitable method ( ) decorated with @JsonCreator (for Enum…
- _anySetter already set to non-null
- Cannot deserialize Class
- Cannot deserialize Proxy class
- Cannot pass null modifier
AI-assisted analysis of FasterXML/jackson-databind@87876ca5c0 (2026-08-11).
Data as JSON: /api/errors/610f77d9f2b43c86.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/tools/jackson/databind/deser/BasicDeserializerFactory.java:925
Class<?> mapClass = type.getRawClass();
// [databind#1853]: Map `Map<ENUM,x>` to `EnumMap<ENUM,x>`
if ((mapClass == Map.class) && keyType.isEnumType()) {
mapClass = EnumMap.class;
type = (MapType) config.getTypeFactory().constructSpecializedType(type, mapClass);
// type = (MapType) config.getTypeFactory().constructMapType(mapClass, keyType, contentType);
}
if (EnumMap.class.isAssignableFrom(mapClass)) {
ValueInstantiator inst;
// 06-Mar-2017, tatu: Should only need to check ValueInstantiator for
// custom sub-classes, see [databind#1544]
if (mapClass == EnumMap.class) {
inst = null;
} else {
inst = findValueInstantiator(ctxt, beanDescRef);
}
if (!keyType.isEnumImplType()) {
throw new IllegalArgumentException("Cannot construct EnumMap; generic (key) type not available");
}
deser = new EnumMapDeserializer(type, inst, null,
contentDeser, contentTypeDeser, null);
}
// Otherwise, generic handler works ok.
/* But there is one more twist: if we are being asked to instantiate
* an interface or abstract Map, we need to either find something
* that implements the thing, or give up.
*
* Note that we do NOT try to guess based on secondary interfaces
* here; that would probably not work correctly since casts would
* fail later on (as the primary type is not the interface we'd
* be implementing)
*/
if (deser == null) {
if (type.isInterface() || type.isAbstract()) {View on GitHub (pinned to 87876ca5c0)