diff --git a/DeepClone.Test/EnumerableCloneTests.cs b/DeepClone.Test/EnumerableCloneTests.cs
new file mode 100644
index 0000000..73714d7
--- /dev/null
+++ b/DeepClone.Test/EnumerableCloneTests.cs
@@ -0,0 +1,75 @@
+// Copyright (c) 2023-2026 ktsu-dev contributors
+
+namespace ktsu.DeepClone.Test;
+
+///
+/// Tests for deep cloning plain sequences and stacks through their extension methods.
+///
+[TestClass]
+public class EnumerableCloneTests
+{
+#pragma warning disable CA1851 // Enumerating the clone more than once is what these tests check
+ ///
+ /// Tests that edits to the items of a cloned sequence survive a second enumeration.
+ ///
+ [TestMethod]
+ public void Enumerable_DeepClone_ShouldKeepEditsAcrossEnumerations()
+ {
+ // Arrange
+ List original = [new() { Id = 1, Name = "Item1" }];
+
+ // Act
+ IEnumerable clone = original.DeepClone();
+ foreach (SimpleObject item in clone)
+ {
+ item.Name = "Edited";
+ }
+
+ // Assert
+ Assert.AreEqual("Edited", clone.First().Name);
+ Assert.AreSame(clone.First(), clone.First());
+ Assert.AreEqual("Item1", original[0].Name);
+ }
+
+ ///
+ /// Tests that a cloned sequence does not change when the source changes afterwards.
+ ///
+ [TestMethod]
+ public void Enumerable_DeepClone_ShouldNotTrackSourceChanges()
+ {
+ // Arrange
+ List original =
+ [
+ new() { Id = 1, Name = "Item1" },
+ new() { Id = 2, Name = "Item2" },
+ ];
+
+ // Act
+ IEnumerable clone = original.DeepClone();
+ original.Clear();
+
+ // Assert
+ Assert.AreEqual(2, clone.Count());
+ }
+#pragma warning restore CA1851
+
+ ///
+ /// Tests that deep cloning a null sequence throws ArgumentNullException.
+ ///
+ [TestMethod]
+ public void Enumerable_DeepClone_NullSource_ShouldThrow()
+ {
+ IEnumerable source = null!;
+ Assert.ThrowsExactly(() => source.DeepClone());
+ }
+
+ ///
+ /// Tests that deep cloning a null stack throws ArgumentNullException.
+ ///
+ [TestMethod]
+ public void Stack_DeepClone_NullSource_ShouldThrow()
+ {
+ Stack source = null!;
+ Assert.ThrowsExactly(() => source.DeepClone());
+ }
+}
diff --git a/DeepClone/DeepCloneContainerExtensions.cs b/DeepClone/DeepCloneContainerExtensions.cs
index 11d5f80..3d46d5f 100644
--- a/DeepClone/DeepCloneContainerExtensions.cs
+++ b/DeepClone/DeepCloneContainerExtensions.cs
@@ -104,8 +104,9 @@ public static void DeepCloneFrom(this IDictionary de
/// A new collection containing deep clones of the original items if they implement IDeepCloneable,
/// otherwise containing the original items.
///
- /// This method returns an IEnumerable sequence of cloned items. To get a specific collection type,
- /// you'll need to convert the result (for example using ToList() or ToArray()).
+ /// The items are cloned when this method is called, so the result is a snapshot: it does not change
+ /// when the source changes, and enumerating it again yields the same cloned instances. To get a
+ /// specific collection type, convert the result (for example using ToList() or ToArray()).
///
/// Example usage:
///
@@ -113,8 +114,13 @@ public static void DeepCloneFrom(this IDictionary de
/// var clonedArray = originalArray.DeepClone().ToArray();
///
///
- public static IEnumerable DeepClone(this IEnumerable source) =>
- source.Select(DeepClone);
+ /// Thrown if source is null.
+ public static IEnumerable DeepClone(this IEnumerable source)
+ {
+ Ensure.NotNull(source);
+
+ return [.. source.Select(DeepClone)];
+ }
///
/// Deep clones a dictionary.
@@ -314,6 +320,11 @@ public static SortedSet DeepClone(this SortedSet source)
/// var clonedStack = originalStack.DeepClone();
///
///
- public static Stack DeepClone(this Stack source) =>
- new(source.Reverse().Select(DeepClone));
+ /// Thrown if source is null.
+ public static Stack DeepClone(this Stack source)
+ {
+ Ensure.NotNull(source);
+
+ return new(source.Reverse().Select(DeepClone));
+ }
}