diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9f8f92ce9b7b108807fcedbab4ad15236b9bb2d..b46c253fb88455a19424af3b7ef448f08dca2263 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,3 @@
-# v2.16.2
+# v2.16.3
 
-* added optional argument to `File.get_value`
-* added `file_contents` schema 
-* added nested configuration sources
-* added `extract_optional`
-* added some syntactic sugar for the source dict
-* now unparseable "type" entries will be returned as-is
-* added `ConfigurationMisconfiguredError`
+* added `ComparableAndHashableByStr`
diff --git a/satella/__init__.py b/satella/__init__.py
index b34264c0170bdade762aeb84e205670aa068b860..9157e8053c94c5086da050d9d01f7b7d18c56a9d 100644
--- a/satella/__init__.py
+++ b/satella/__init__.py
@@ -1 +1 @@
-__version__ = '2.16.2'
+__version__ = '2.16.3'
diff --git a/satella/coding/structures/__init__.py b/satella/coding/structures/__init__.py
index e0efee2bedfa722402e4b9061e84ebb95675d5cb..95932389fdb433567659ed35da2ee0af9388b8ac 100644
--- a/satella/coding/structures/__init__.py
+++ b/satella/coding/structures/__init__.py
@@ -6,7 +6,7 @@ from .heaps import Heap, SetHeap, TimeBasedHeap, TimeBasedSetHeap
 from .immutable import Immutable, frozendict
 from .mixins import OmniHashableMixin, ReprableMixin, StrEqHashableMixin, ComparableIntEnum, \
     HashableIntEnum, ComparableAndHashableBy, ComparableAndHashableByInt, ComparableEnum, \
-    HashableMixin
+    HashableMixin, ComparableAndHashableByStr
 from .proxy import Proxy
 from .queues import Subqueue
 from .ranking import Ranking
@@ -41,6 +41,7 @@ __all__ = [
     'ComparableIntEnum',
     'ComparableAndHashableBy',
     'HashableIntEnum',
+    'ComparableAndHashableByStr',
     'DirtyDict',
     'SortedList',
     'SelfCleaningDefaultDict',
diff --git a/satella/coding/structures/mixins/__init__.py b/satella/coding/structures/mixins/__init__.py
index 4f300d6db764b442d63f59b8cca35b1c732895e9..85e9f77bb2d947421f53b62a022f34c577c52fa0 100644
--- a/satella/coding/structures/mixins/__init__.py
+++ b/satella/coding/structures/mixins/__init__.py
@@ -1,8 +1,9 @@
 from .enums import ComparableEnum, ComparableIntEnum, HashableIntEnum
 from .hashable import ComparableAndHashableBy, ComparableAndHashableByInt, \
-    OmniHashableMixin, HashableMixin
+    OmniHashableMixin, HashableMixin, ComparableAndHashableByStr
 from .strings import ReprableMixin, StrEqHashableMixin
 
 __all__ = ['ComparableIntEnum', 'ComparableEnum', 'ComparableAndHashableBy',
            'HashableIntEnum', 'ComparableAndHashableByInt', 'OmniHashableMixin',
-           'ReprableMixin', 'StrEqHashableMixin', 'HashableMixin']
+           'ReprableMixin', 'StrEqHashableMixin', 'HashableMixin',
+           'ComparableAndHashableByStr']
diff --git a/satella/coding/structures/mixins/hashable.py b/satella/coding/structures/mixins/hashable.py
index aac2d882459fe16b2d1d8bbbe1c4048a63c9a07d..930ca386cd1319a136686150a8777eb0dcf824c2 100644
--- a/satella/coding/structures/mixins/hashable.py
+++ b/satella/coding/structures/mixins/hashable.py
@@ -97,6 +97,37 @@ class ComparableAndHashableByInt(metaclass=ABCMeta):
         return int(self) >= int(other)
 
 
+class ComparableAndHashableByStr(metaclass=ABCMeta):
+    """
+    A mix-in. Provides comparision (lt, gt, ge, le, eq) and hashing by __str__ of this class.
+    Also, will make this class equal to strings that return the same value.
+    """
+
+    __slots__ = ()
+
+    @abstractmethod
+    def __str__(self) -> str:
+        ...
+
+    def __hash__(self):
+        return hash(str(self))
+
+    def __eq__(self, other: 'ComparableAndHashableByInt') -> bool:
+        return str(self) == str(other)
+
+    def __lt__(self, other: 'ComparableAndHashableByInt') -> bool:
+        return str(self) < str(other)
+
+    def __le__(self, other: 'ComparableAndHashableByInt') -> bool:
+        return str(self) <= str(other)
+
+    def __gt__(self, other: 'ComparableAndHashableByInt') -> bool:
+        return str(self) > str(other)
+
+    def __ge__(self, other: 'ComparableAndHashableByInt') -> bool:
+        return str(self) >= str(other)
+
+
 class OmniHashableMixin(metaclass=ABCMeta):
     """
     A mix-in. Provides hashing and equal comparison for your own class using specified fields.
diff --git a/tests/test_coding/test_structures.py b/tests/test_coding/test_structures.py
index 9d7a7605b8b5fcb1f1aa1a6f40d068b8ee031b4a..82e210d3aa97ac6fbbf0eda0a57f459ebc3eba7d 100644
--- a/tests/test_coding/test_structures.py
+++ b/tests/test_coding/test_structures.py
@@ -14,7 +14,8 @@ from satella.coding.structures import TimeBasedHeap, Heap, typednamedtuple, \
     DirtyDict, KeyAwareDefaultDict, Proxy, ReprableMixin, TimeBasedSetHeap, ExpiringEntryDict, SelfCleaningDefaultDict, \
     CacheDict, StrEqHashableMixin, ComparableIntEnum, HashableIntEnum, ComparableAndHashableBy, \
     ComparableAndHashableByInt, SparseMatrix, ExclusiveWritebackCache, Subqueue, \
-    CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict, PushIterable
+    CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict, PushIterable, \
+    ComparableAndHashableByStr
 
 
 class TestMisc(unittest.TestCase):
@@ -219,6 +220,22 @@ class TestMisc(unittest.TestCase):
         self.assertFalse(Vector(1) == Vector(2))
         self.assertEqual(hash(Vector(1)), hash(1))
 
+    def test_comparable_and_hashable_by_str(self):
+        class Vector(ComparableAndHashableByStr):
+
+            def __str__(self) -> str:
+                return self.a
+
+            def __init__(self, a):
+                self.a = a
+
+        self.assertTrue(Vector('a') < Vector('ab'))
+        self.assertTrue(Vector('a') <= Vector('a'))
+        self.assertFalse(Vector('a') > Vector('b'))
+        self.assertFalse(Vector('a') >= Vector('b'))
+        self.assertFalse(Vector('a') == Vector('b'))
+        self.assertEqual(hash(Vector('a')), hash('a'))
+
     def test_hashable_int_enum(self):
         class A(HashableIntEnum):
             A = 0