google/gson · error · JsonIOException

Invalid EnumMap type: {type}

Error message

Invalid EnumMap type: {type}

What it means

The EnumMap factory requires a ParameterizedType whose first argument is a Class (the key enum type). If the key argument is itself generic/parameterized/wildcard, the enum class cannot be determined and JsonIOException is thrown.

Source

Thrown at gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java:206

            throw new JsonIOException("Invalid EnumSet type: " + type);
          }
        } else {
          throw new JsonIOException("Invalid EnumSet type: " + type);
        }
      };
    }
    // Only support creation of EnumMap, but not of custom subtypes; for them type parameters
    // and constructor parameter might have completely different meaning
    else if (rawType == EnumMap.class) {
      return () -> {
        if (type instanceof ParameterizedType) {
          Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
          if (elementType instanceof Class) {
            @SuppressWarnings({"unchecked", "rawtypes"})
            T map = (T) new EnumMap((Class) elementType);
            return map;
          } else {
            throw new JsonIOException("Invalid EnumMap type: " + type);
          }
        } else {
          throw new JsonIOException("Invalid EnumMap type: " + type);
        }
      };
    }

    return null;
  }

  private static <T> ObjectConstructor<T> newDefaultConstructor(
      Class<? super T> rawType, FilterResult filterResult) {
    // Cannot invoke constructor of abstract class
    if (Modifier.isAbstract(rawType.getModifiers())) {
      return null;
    }

    Constructor<? super T> constructor;

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Use a concrete enum key: EnumMap<MyEnum, String>.
  2. Build an explicit TypeToken: new TypeToken<EnumMap<MyEnum, String>>(){}.
  3. Register an InstanceCreator<EnumMap<MyEnum, V>>.
  4. Avoid wildcard/type-variable keys on EnumMap fields.

Example fix

// before
EnumMap<? extends Color, Integer> counts;

// after
EnumMap<Color, Integer> counts;
Defensive patterns

Strategy: validation

Validate before calling

if (type instanceof ParameterizedType
    && ((ParameterizedType) type).getActualTypeArguments()[0] instanceof Class) {
  // safe EnumMap construction
}

Type guard

boolean isConcreteEnumMapType(Type t) {
  if (!(t instanceof ParameterizedType)) return false;
  Type k = ((ParameterizedType) t).getActualTypeArguments()[0];
  return k instanceof Class && ((Class<?>) k).isEnum();
}

Try / catch

try {
  return gson.fromJson(json, type);
} catch (JsonIOException ex) {
  if (ex.getMessage().startsWith("Invalid EnumMap type")) {
    // register InstanceCreator and retry
  }
  throw ex;
}

Prevention

When it happens

Trigger: Field declared EnumMap<MyEnum<?>, V>, EnumMap<K, V> with K a type variable, or a TypeToken losing the concrete enum key class; reflective construction where the key type is captured generically.

Common situations: Generic map utilities; wildcard key bounds; frameworks binding EnumMap<K,V> generically.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/db66c5aa19e6f324.json. Report an issue: GitHub.