diff --git a/docs/api/collections.md b/docs/api/collections.md
index 0025bc1..7aa7ecf 100644
--- a/docs/api/collections.md
+++ b/docs/api/collections.md
@@ -3335,7 +3335,9 @@ frees.
LRU semantics require a lookup to count as a *use*. The indexer getter and `TryGet` therefore
**promote the entry to most-recently-used**, which reorders the recency list and invalidates any
-in-progress enumerator (matching "collection was modified" semantics). To inspect the cache without
+in-progress enumerator (matching "collection was modified" semantics). The one exception is a hit on
+the entry that is *already* most-recently-used: there is nothing to reorder, so the promotion is a
+no-op and active enumerators stay valid. To inspect the cache without
disturbing recency order — and without invalidating an active enumerator — use `TryPeek`,
`ContainsKey`, or the `TryPeekLeastRecentlyUsed` / `TryPeekMostRecentlyUsed` inspectors.
diff --git a/src/Celerity/Collections/LruCache.cs b/src/Celerity/Collections/LruCache.cs
index 8812db6..5e1c0e9 100644
--- a/src/Celerity/Collections/LruCache.cs
+++ b/src/Celerity/Collections/LruCache.cs
@@ -31,7 +31,9 @@ namespace Celerity.Collections;
///
/// Reads are mutating. LRU semantics require a lookup to count as a use, so the indexer getter
/// and promote the entry to most-recently-used and therefore
-/// invalidate any in-progress enumerator (matching "collection was modified" semantics). Use
+/// invalidate any in-progress enumerator (matching "collection was modified" semantics) — except when
+/// the entry is already the most-recently-used one, where the promotion is a no-op that leaves
+/// the recency order and any active enumerator untouched. Use
/// or to inspect the cache
/// without disturbing recency order.
///
@@ -155,7 +157,10 @@ public TValue? this[TKey key]
/// value of .
///
/// true if the key was found; otherwise false.
- /// A hit reorders the recency list and therefore invalidates active enumerators.
+ ///
+ /// A hit reorders the recency list and therefore invalidates active enumerators, unless the entry
+ /// is already the most-recently-used one — that promotion is a no-op and leaves them valid.
+ ///
public bool TryGet(TKey key, out TValue? value)
{
if (!_index.TryGetValue(key, out int node))
@@ -346,9 +351,12 @@ public bool TryPeekMostRecentlyUsed(out TKey? key, out TValue? value)
///
/// Returns an allocation-free struct enumerator that yields each entry in
/// most-recently-used to least-recently-used order. Enumeration is a peek: it does not
- /// change recency. If the cache is modified during enumeration — including by a mutating read
- /// ( or the indexer getter) —
- /// throws .
+ /// change recency. throws
+ /// when the entry set or the recency order changed since the enumerator was taken: an insert, an
+ /// eviction, a , a , or any read or write that
+ /// promoted an entry which was not already most-recently-used. Overwriting the value of an entry
+ /// without moving it is not a structural change and leaves active enumerators valid, matching the
+ /// rest of the library.
///
/// A struct enumerator over this cache.
public Enumerator GetEnumerator() => new Enumerator(this);