Course contents

WeakHashMap, IdentityHashMap and EnumMap

WeakHashMap, IdentityHashMap, EnumMap and case-insensitive Map choices, including GC behaviour, reference equality and enum-key performance.

PremiumGood to knowLesson13 min readCoreReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: luggage tags, mirror IDs and mail slots
  2. WeakHashMap under the hood
  3. IdentityHashMap: reference equality on purpose
  4. EnumMap: one slot per enum constant
  5. Case-insensitive String keys
  6. Advanced: choosing among the special maps
  7. How to say it in the interview

🗺️ What are WeakHashMap, IdentityHashMap and EnumMap?

WeakHashMap, IdentityHashMap and EnumMap are special-purpose Map implementations that change one of the usual HashMap assumptions. WeakHashMap lets keys disappear when the rest of the application no longer strongly references them, IdentityHashMap compares keys with ==, and EnumMap stores enum keys in a compact array. If HashMap is the normal toolbox drawer, these are the oddly shaped tools you use when the requirement is oddly shaped too.

For this lesson, we'll focus on how WeakHashMap uses WeakReference and ReferenceQueue, why it is not a general cache, when reference equality makes IdentityHashMap the right answer, why EnumMap is the best default for enum keys, and how to build maps with case-insensitive String keys. Interviewers ask these because they look like trivia until you hit the edge cases. Then the answer tells me whether you understand object lifetime, equality and the real contract of Map.

Below the line (out of scope)

The 30-second answer

Use WeakHashMap when the key's object lifetime should control whether metadata stays in the map: keys are wrapped in weak references, the GC clears them, and the map removes stale entries by draining a ReferenceQueue during normal operations. Do not treat it as a cache: string literals, interned strings and boxed small integers may never become unreachable, and a value that points back to its key keeps the key alive. Use IdentityHashMap when == is the correct equality rule, such as graph traversal, serialization or proxy bookkeeping; it intentionally violates the normal Map contract and stores alternating keys and values in a flat Object[] with linear probing. Use EnumMap for enum keys: it stores values in an array indexed by ordinal(), iterates in declaration order, rejects null keys and is usually the fastest map for enum keys. For case-insensitive strings, choose either a TreeMap<>(String.CASE_INSENSITIVE_ORDER) or normalize keys with toLowerCase(Locale.ROOT) before a HashMap lookup.

What you’ll learn

  • Explain how WeakHashMap stores keys through weak references and removes stale entries through a ReferenceQueue
  • Avoid the WeakHashMap traps: interned keys, boxed small integers, and values that strongly reference their keys
  • Use IdentityHashMap only when reference equality is the requirement, not as a faster HashMap
  • Describe EnumMap as an array indexed by enum ordinal() and know why it preserves declaration order
  • Choose a case-insensitive map strategy: TreeMap(String.CASE_INSENSITIVE_ORDER), normalized HashMap, or a library map
  • Compare the special map implementations by equality rule, ordering, null handling and interview use case

Interview radar

Asked sometimes: Which map would you use for keys compared by reference equality? Which map lets entries disappear when keys are no longer referenced? Senior rounds probe: Why WeakHashMap can still leak, why IdentityHashMap breaks the usual equality contract, and why EnumMap is an array, not a hash table. Production angle: A metadata map that grows with object lifetime is useful. A weak map pretending to be a cache usually becomes a confusing memory bug.

01Picture it first: luggage tags, mirror IDs and mail slots

Think of these maps as three different reception desks. WeakHashMap keeps a luggage tag that falls off when the suitcase is gone. IdentityHashMap checks the physical badge, not the name printed on it. EnumMap has one fixed mail slot per enum constant, so MONDAY always goes to slot 0 if it was declared first.

Let's get the WeakHashMap picture right first. The key is weak; the value is not.

Fig. 1

A WeakHashMap entry holds its key through a WeakReference registered with a ReferenceQueue; when the application drops the last strong reference, GC clears the weak key and the next map operation removes the stale entry while the value was always strongly held

A WeakHashMap entry holds its key through a WeakReference registered with a ReferenceQueue; when the application drops the last strong reference, GC clears the weak key and the next map operation removes the stale entry while the value was always strongly held

Notice the shape. The map does not remove the entry at the exact instant the key becomes unreachable. The GC clears the weak reference and enqueues it, then a later map operation drains the queue and unlinks the stale entry.

02WeakHashMap under the hood

WeakHashMap<K,V> is a hash table whose entry extends WeakReference<Object>. The referent is the key. The entry also stores the value, the cached hash and the next pointer in the bucket chain.

Try it yourself first

Before reading the answer, predict which entries are likely to disappear after GC and which ones are likely to stay.

import java.util.Map;
import java.util.WeakHashMap;

public class WeakKeysDemo {
    public static void main(String[] args) throws Exception {
        Map<Object, String> metadata = new WeakHashMap<>();

        Object request = new Object();
        String literal = "tenant-a";
        Integer small = Integer.valueOf(42);

        metadata.put(request, "request metadata");
        metadata.put(literal, "literal metadata");
        metadata.put(small, "small integer metadata");

        request = null;
        System.gc();
        Thread.sleep(100);

        metadata.size(); // touches the map and gives it a chance to expunge stale entries
        System.out.println(metadata);
    }
}

The request entry is the one that can disappear, because after request = null nothing else strongly refers to that object. The string literal is held by the class's constant data for as long as the class is loaded. The small Integer comes from IntegerCache for values from -128 to 127, so the cached object is strongly reachable through the JDK cache.

Notice three things:

  • WeakHashMap calls an internal expungeStaleEntries while serving normal operations such as get, put, remove, size and table access. Cleanup is lazy from your point of view.
  • The value is a strong reference. If the value points back to the key, directly or through a graph, the key is still reachable and the entry does not disappear.
  • GC timing is not a business rule. You cannot write correctness logic that depends on an entry vanishing right after System.gc().

A real stale entry goes through four steps. The application drops its last strong reference to the key. The GC discovers that only weak references point at the key, clears the weak reference, and enqueues the entry's reference on the map's queue. A later map operation drains that queue, finds the original entry and removes it from the bucket.

That makes WeakHashMap useful for metadata keyed by object lifetime. For example, a framework might attach analysis data to AST nodes, parsed templates or connection wrapper objects without wanting a side table to keep those objects alive. For class-specific metadata, ClassValue<T> is often the cleaner API because the JVM owns the class-lifetime association.

In the real world

The first weak-map bug I saw in a code review was a "temporary" cache keyed by Class<?>. The values included helper objects that held the same Class<?> for logging and reflection. That one back-reference turned the weak-key map into a strong-key map, and old plugin class loaders stayed alive after reloads. The fix was either ClassValue or values that did not retain the key.

03IdentityHashMap: reference equality on purpose

Premium lesson

Keep reading with the Java Pass

The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.

  • EnumMap: one slot per enum constant
  • Case-insensitive String keys
  • Advanced: choosing among the special maps
  • How to say it in the interview

From ₹199 · one-time payment · No auto-renewal

Practise this topicMaps: interview questions & scenarios
Further reading (8)