diff --git a/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs b/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs
new file mode 100644
index 00000000..d59470d9
--- /dev/null
+++ b/src/Spring/Spring.Core/Collections/Generic/AbstractDictionary.cs
@@ -0,0 +1,110 @@
+#region License
+
+/*
+ * Copyright © 2015-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Spring.Collections.Generic
+{
+ ///
+ /// Partial IDictionary implementation which serves as a common base for final implementations.
+ ///
+ /// Zbynek Vyskovsky, kvr@centrum.cz
+ public abstract class AbstractDictionary: System.Collections.Generic.IDictionary
+ {
+ public abstract void Add(TKey key, TValue value);
+
+ public abstract bool ContainsKey(TKey key);
+
+ public abstract bool Remove(TKey key);
+
+ public abstract bool TryGetValue(TKey key, out TValue value);
+
+ public abstract void Clear();
+
+ public bool Contains(KeyValuePair item)
+ {
+ TValue value;
+ return TryGetValue(item.Key, out value) && (item.Value == null ? value == null : item.Value.Equals(value));
+ }
+
+ public void CopyTo(KeyValuePair[] array, int arrayIndex)
+ {
+ }
+
+ public abstract int Count { get; }
+
+ public bool IsReadOnly
+ {
+ get {
+ return false;
+ }
+ }
+
+ public abstract bool Remove(KeyValuePair item);
+
+ public IEnumerator> GetEnumerator()
+ {
+ return EntriesSet().GetEnumerator();
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ return EntriesSet().GetEnumerator();
+ }
+
+ public ICollection Keys
+ {
+ get {
+ return EntriesSet().Select((KeyValuePair entry) => entry.Key).ToList();
+ }
+ }
+
+ public ICollection Values
+ {
+ get {
+ return EntriesSet().Select((KeyValuePair entry) => entry.Value).ToList();
+ }
+ }
+
+ public TValue this[TKey key]
+ {
+ get {
+ TValue value;
+ if (!TryGetValue(key, out value))
+ throw new KeyNotFoundException("Key not found in map: "+key);
+ return value;
+ }
+ set {
+ Add(key, value);
+ }
+ }
+
+ public void Add(KeyValuePair item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ protected abstract IEnumerable> EntriesSet();
+ }
+}
diff --git a/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs b/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs
new file mode 100644
index 00000000..f29e5d28
--- /dev/null
+++ b/src/Spring/Spring.Core/Collections/Generic/LinkedHashDictionary.cs
@@ -0,0 +1,137 @@
+#region License
+
+/*
+ * Copyright © 2015-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Spring.Collections.Generic
+{
+ ///
+ /// IDictionary implementation which preserves the order of inserted items.
+ ///
+ /// Zbynek Vyskovsky, kvr@centrum.cz
+ public class LinkedHashDictionary: AbstractDictionary
+ {
+ public override void Add(TKey key, TValue value)
+ {
+ Node node;
+ if (items.TryGetValue(key, out node)) {
+ node.value = value;
+ }
+ else {
+ node = new Node();
+ node.key = key;
+ node.value = value;
+ if ((node.previousLinked = linkedTail) != null)
+ node.previousLinked.nextLinked = node;
+ node.nextLinked = null;
+ linkedTail = node;
+ if (linkedHead == null)
+ linkedHead = node;
+ items.Add(key, node);
+ }
+ }
+
+ public override bool ContainsKey(TKey key)
+ {
+ return items.ContainsKey(key);
+ }
+
+ public override bool Remove(TKey key)
+ {
+ Node node;
+ if (!items.TryGetValue(key, out node))
+ return false;
+
+ if (node.previousLinked != null) {
+ node.previousLinked.nextLinked = node.nextLinked;
+ }
+ else {
+ linkedHead = node.nextLinked;
+ }
+
+ if (node.nextLinked != null) {
+ node.nextLinked.previousLinked = node.previousLinked;
+ }
+ else {
+ linkedTail = node.previousLinked;
+ }
+
+ return true;
+ }
+
+ public override bool TryGetValue(TKey key, out TValue value)
+ {
+ Node node;
+ if (!items.TryGetValue(key, out node)) {
+ value = default(TValue);
+ return false;
+ }
+ value = node.value;
+ return true;
+ }
+
+ public override void Clear()
+ {
+ items.Clear();
+ linkedHead = null;
+ linkedTail = null;
+ }
+
+ public override bool Remove(KeyValuePair item)
+ {
+ Node node;
+ if (!items.TryGetValue(item.Key, out node))
+ return false;
+ if (!node.value.Equals(item.Value))
+ return false;
+ return Remove(item.Key);
+ }
+
+ public override int Count
+ {
+ get { return items.Count; }
+ }
+
+ protected class Node
+ {
+ public TKey key;
+ public TValue value;
+
+ public Node previousLinked;
+ public Node nextLinked;
+ }
+
+ protected override IEnumerable> EntriesSet()
+ {
+ List> entries = new List>();
+ for (Node node = linkedHead; node != null; node = node.nextLinked)
+ entries.Add(new KeyValuePair(node.key, node.value));
+ return entries;
+ }
+
+ private Node linkedHead = null;
+ private Node linkedTail = null;
+
+ private Dictionary items = new Dictionary();
+ }
+}
diff --git a/test/Spring/Spring.Core.Tests/Collections/Generic/Test/LinkedHashDictionaryTest.cs b/test/Spring/Spring.Core.Tests/Collections/Generic/Test/LinkedHashDictionaryTest.cs
new file mode 100644
index 00000000..7c6536e0
--- /dev/null
+++ b/test/Spring/Spring.Core.Tests/Collections/Generic/Test/LinkedHashDictionaryTest.cs
@@ -0,0 +1,71 @@
+#region License
+
+/*
+ * Copyright © 2015-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Spring.Collections.Generic
+using NUnit.Framework;
+
+namespace Spring.Collections.Generic.Test
+{
+ ///
+ /// This class contains tests for LinkedHashDictionary
+ ///
+ /// Zbynek Vyskovsky, kvr@centrum.cz
+ [TestFixture]
+ public class LinkedHashDictionaryTest
+ {
+ [Test]
+ public void TestSunnyDay()
+ {
+ IDictionary td = new LinkedHashDictionary();
+ td.Add(0, "a");
+ td.Add(1, "b");
+ td.Add(2, "c");
+ td.Add(1, "b2");
+ td.Add(3, "d");
+ td.Add(4, "e");
+ Assert.IsTrue(td.ContainsKey(0));
+ Assert.IsTrue(td.ContainsKey(1));
+ Assert.IsTrue(td.ContainsKey(2));
+ Assert.IsTrue(td.ContainsKey(3));
+ Assert.IsTrue(td.ContainsKey(4));
+ Assert.AreEqual("a", td[0]);
+ Assert.AreEqual("b2", td[1]);
+ int[] keys = td.Keys.ToArray();
+ Assert.AreEqual(5, keys.Length);
+ Assert.AreEqual(0, keys[0]);
+ Assert.AreEqual(1, keys[1]);
+ Assert.AreEqual(2, keys[2]);
+ Assert.AreEqual(3, keys[3]);
+ Assert.AreEqual(4, keys[4]);
+ td.Remove(3);
+ td.Remove(2);
+ Assert.AreEqual(3, td.Count);
+ td.Remove(1);
+ Assert.AreEqual(2, td.Count);
+ td.Remove(4);
+ td.Remove(0);
+ Assert.AreEqual(0, td.Count);
+ Assert.AreEqual(0, td.Keys.Count);
+ }
+ }
+}