diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs
deleted file mode 100644
--- a/bench/BenchAll.hs
+++ /dev/null
@@ -1,58 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Main where
-
-import Control.DeepSeq
-import Criterion.Main
-import Data.Binary
-import Data.ByteString.Lazy (ByteString)
-import Data.Identifiers
-    
-genNames :: Int -> [String]
-genNames n = map show . take n $ ([100000000..] :: [Int])
-
-decodeI :: ByteString -> Identifiers Word32 String
-decodeI = decode
-
-fromListI :: [String] -> Identifiers Word32 String
-fromListI = fromList
-
-main :: IO ()
-main = do
-    let setA = genNames 1000
-        setB = genNames 10000
-        setC = genNames 100000
-        idA = fromListI setA
-        idB = fromListI setB
-        idC = fromListI setC
-        encA = encode idA
-        encB = encode idB
-        encC = encode idC
-    defaultMain
-        [ bgroup "fromList"
-            [ setA `deepseq` bench "  1,000" $ nf fromListI setA
-            , setB `deepseq` bench " 10,000" $ nf fromListI setB
-            , setC `deepseq` bench "100,000" $ nf fromListI setC
-            ]
-        , bgroup "lookupKey"
-            [ idA `deepseq` bench "  1,000" $ nf (`lookupKey` 500)   idA
-            , idB `deepseq` bench " 10,000" $ nf (`lookupKey` 5000)  idB
-            , idC `deepseq` bench "100,000" $ nf (`lookupKey` 50000) idC
-            ]
-        , bgroup "lookupId"
-            [ bench "  1,000" $ nf (`lookupId` "100000500") idA
-            , bench " 10,000" $ nf (`lookupId` "100005000") idB
-            , bench "100,000" $ nf (`lookupId` "100050000") idC
-            ]
-        , bgroup "encode"
-            [ bench "  1,000" $ nf encode idA
-            , bench " 10,000" $ nf encode idB
-            , bench "100,000" $ nf encode idC
-            ]
-        , bgroup "decode"
-            [ encA `deepseq` bench "  1,000" $ nf decodeI encA
-            , encB `deepseq` bench " 10,000" $ nf decodeI encB
-            , encC `deepseq` bench "100,000" $ nf decodeI encC
-            ]
-        ]
-
diff --git a/bench/Identifiers.hs b/bench/Identifiers.hs
deleted file mode 100644
--- a/bench/Identifiers.hs
+++ /dev/null
@@ -1,36 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Main where
-
-import Control.DeepSeq
-import Criterion.Main
-import Data.Binary
-import Data.Identifiers
-import Data.Text (Text, pack)
-    
-genNames :: Int -> [Text]
-genNames n = map (pack . show) . take n $ ([100000000..] :: [Int])
-
-fromListI :: [Text] -> Identifiers Word32 Text
-fromListI = fromList
-
-main :: IO ()
-main = do
-    let setA = genNames 2000
-        setB = genNames 200000
-        idA = fromListI setA
-        idB = fromListI setB
-    defaultMain
-        [ bgroup "fromList"
-            [ setA `deepseq` bench "  2,000" $ nf fromListI setA
-            , setB `deepseq` bench "200,000" $ nf fromListI setB
-            ]
-        , bgroup "lookupKey"
-            [ idA `deepseq` bench "  2,000" $ nf (`lookupKey` 500)   idA
-            , idB `deepseq` bench "200,000" $ nf (`lookupKey` 50000) idB
-            ]
-        , bgroup "lookupId"
-            [ bench "  2,000" $ nf (`lookupId` "100000500") idA
-            , bench "200,000" $ nf (`lookupId` "100050000") idB
-            ]
-        ]
-
diff --git a/bench/IdentifiersHashable.hs b/bench/IdentifiersHashable.hs
new file mode 100644
--- /dev/null
+++ b/bench/IdentifiersHashable.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Control.DeepSeq
+import Criterion.Main
+import Data.Binary
+import Data.Identifiers.Hashable
+import Data.Text (Text, pack)
+    
+genNames :: Int -> [Text]
+genNames n = map (pack . show) . take n $ ([100000000..] :: [Int])
+
+fromListI :: [Text] -> Identifiers Word32 Text
+fromListI = fromList
+
+main :: IO ()
+main = do
+    let setA = genNames 2000
+        setB = genNames 200000
+        idA = fromListI setA
+        idB = fromListI setB
+    defaultMain
+        [ bgroup "fromList"
+            [ setA `deepseq` bench "  2,000" $ nf fromListI setA
+            , setB `deepseq` bench "200,000" $ nf fromListI setB
+            ]
+        , bgroup "lookupKey"
+            [ idA `deepseq` bench "  2,000" $ nf (`lookupKey` 500)   idA
+            , idB `deepseq` bench "200,000" $ nf (`lookupKey` 50000) idB
+            ]
+        , bgroup "lookupId"
+            [ bench "  2,000" $ nf (`lookupId` "100000500") idA
+            , bench "200,000" $ nf (`lookupId` "100050000") idB
+            ]
+        ]
+
diff --git a/identifiers.cabal b/identifiers.cabal
--- a/identifiers.cabal
+++ b/identifiers.cabal
@@ -1,5 +1,5 @@
 name:                identifiers
-version:             0.3.1.0
+version:             0.4.0.0
 synopsis:            Numeric identifiers for values.
 description:         Useful for situations where repeated-storage requirements
                      of values become too costly.
@@ -16,7 +16,7 @@
   location:            https://github.com/awagner83/identifiers.git
 
 library
-  exposed-modules:     Data.Identifiers Data.Identifiers.ListLike
+  exposed-modules:     Data.Identifiers.Hashable Data.Identifiers.ListLike
   other-modules:       Data.TrieMap
   build-depends:       base >=4.6 && <4.8,
                        binary ==0.7.*,
@@ -31,24 +31,10 @@
   default-language:    Haskell2010
   ghc-options:         -Wall -O2 -funbox-strict-fields
 
-benchmark bench-builder-all
-  type:                exitcode-stdio-1.0
-  hs-source-dirs:      bench
-  main-is:             BenchAll.hs
-  build-depends:       base >=4.6 && <4.8,
-                       criterion,
-                       binary ==0.7.*,
-                       cereal <0.5,
-                       deepseq ==1.3.*,
-                       bytestring ==0.10.*,
-                       identifiers
-  default-language:    Haskell2010
-  ghc-options:         -Wall -rtsopts -with-rtsopts=-t
-
-benchmark identifiers-generic
+benchmark identifiers-hashable
   type:                exitcode-stdio-1.0
   hs-source-dirs:      bench
-  main-is:             Identifiers.hs
+  main-is:             IdentifiersHashable.hs
   build-depends:       base >=4.6 && <4.8,
                        criterion,
                        binary ==0.7.*,
diff --git a/src/Data/Identifiers.hs b/src/Data/Identifiers.hs
deleted file mode 100644
--- a/src/Data/Identifiers.hs
+++ /dev/null
@@ -1,145 +0,0 @@
-module Data.Identifiers
-    ( Identifiers ()
-    
-    -- * Construction
-    , empty
-    , fromList
-    
-    -- * Insertion
-    , insert
-    , insertMany
-
-    -- * Info
-    , size
-    
-    -- * Extraction
-    , toList
-
-    -- * Lookups
-    , lookupId
-    , lookupKey
-    , lookupKeys
-    , unsafeLookupId
-    , unsafeLookupKey
-    , (!)
-
-    -- * Properties
-    , prop_hasId
-    , prop_stableId
-    , prop_keyRetrieval
-    , prop_keyRetrievalUnsafe
-    , prop_idempotent
-
-    ) where
-
-import Control.Applicative hiding (empty)
-import Control.DeepSeq
-import Data.Binary
-import Data.List (foldl')
-import Data.Hashable
-import Data.HashMap.Lazy (HashMap)
-import Data.Maybe
-import Data.Sequence (Seq, (|>))
-import Data.Serialize (Serialize)
-import qualified Data.HashMap.Lazy as H
-import qualified Data.Sequence as S
-import qualified Data.Serialize as C
-
-
-data Identifiers i a = Identifiers { ids   :: !(HashMap a i)
-                                   , names :: !(Seq a)
-                                   } deriving Eq
-
-instance Show a => Show (Identifiers i a) where
-    show s = "insertMany empty " ++ show (H.keys (ids s))
-
-instance (Binary i, Eq a, Hashable a, Binary a) => Binary (Identifiers i a) where
-    put s = put (H.toList $ ids s) >> put (names s)
-    get = Identifiers <$> (H.fromList <$> get) <*> get
-
-instance (Serialize i, Eq a, Hashable a, Serialize a) => Serialize (Identifiers i a) where
-    put s = C.put (H.toList $ ids s) >> C.put (names s)
-    get = Identifiers <$> (H.fromList <$> C.get) <*> C.get
-
-instance (NFData i, NFData a) => NFData (Identifiers i a) where
-    rnf (Identifiers i n) = rnf (i, n)
-
--- | The empty Identifiers
-empty :: Identifiers i a
-empty = Identifiers H.empty S.empty
-
--- | New Identifiers from list
-fromList :: (Integral i, Hashable a, Eq a) => [a] -> Identifiers i a
-fromList = insertMany empty
-
--- | Insert item into set (given it a new id)
-insert :: (Integral i, Hashable a, Eq a) => Identifiers i a -> a -> Identifiers i a
-insert xs v = case H.lookup v (ids xs) of
-        Just _  -> xs
-        Nothing -> Identifiers (H.insert v next $ ids xs) (names xs |> v)
-    where next = fromIntegral $ S.length $ names xs
-
--- | Insert many items into set
-insertMany :: (Integral i, Hashable a, Eq a) => Identifiers i a -> [a] -> Identifiers i a
-insertMany = foldl' insert
-
--- | New List from Identifiers
-toList :: Identifiers i a -> [a]
-toList = H.keys . ids
-
--- | Find id for given key
-lookupId :: (Hashable a, Eq a) => Identifiers i a -> a -> Maybe i
-lookupId = flip H.lookup . ids
-
-size :: Identifiers i a -> Int
-size = S.length . names
-
-unsafeLookupId :: (Hashable a, Eq a) => Identifiers i a -> a -> i
-unsafeLookupId = (H.!) . ids
-
--- | Find key for given id
-lookupKey :: (Integral i) => Identifiers i a -> i -> Maybe a
-lookupKey ident x = let xs = names ident
-                    in if S.length xs < fromIntegral x
-                       then Nothing
-                       else Just $ unsafeLookupKey ident x
-
--- | Given many ids, return many keys
-lookupKeys :: (Integral i) => Identifiers i a -> [i] -> [a]
-lookupKeys s = mapMaybe (lookupKey s)
-
-unsafeLookupKey :: Integral i => Identifiers i a -> i -> a
-unsafeLookupKey xs x = S.index (names xs) (fromIntegral x)
-
-(!) :: Integral i => Identifiers i a -> i -> a
-(!) = unsafeLookupKey
-
--- | Items inserted are given ids
-prop_hasId :: String -> Bool
-prop_hasId x = isJust . lookupId (insert (empty :: Identifiers Int String) x) $ x
-
--- | Inserted items have stable ids
-prop_stableId :: String -> Bool
-prop_stableId x = isJust a && a == b
-    where a = lookupId firstSet x
-          b = lookupId secondSet x
-          firstSet = insert (empty :: Identifiers Int String) x
-          secondSet = insert firstSet x
-
--- | Given id can be used to fetch inserted item
-prop_keyRetrievalUnsafe :: [String] -> Bool
-prop_keyRetrievalUnsafe xs = all (\x -> ret x == x) xs
-    where ret = unsafeLookupKey s . unsafeLookupId s
-          s = insertMany (empty :: Identifiers Int String) xs
-
--- | Given id can be used to fetch inserted item
-prop_keyRetrieval :: [String] -> Bool
-prop_keyRetrieval xs = all (\x -> ret x == Just (Just x)) xs
-    where ret x = lookupKey s <$> lookupId s x
-          s = insertMany (empty :: Identifiers Int String) xs
-
--- | Inserting something more than once does not change the set
-prop_idempotent :: String -> Bool
-prop_idempotent x = insert (empty :: Identifiers Int String) x
-                        == insert (insert empty x) x
-
diff --git a/src/Data/Identifiers/Hashable.hs b/src/Data/Identifiers/Hashable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Identifiers/Hashable.hs
@@ -0,0 +1,145 @@
+module Data.Identifiers.Hashable
+    ( Identifiers ()
+    
+    -- * Construction
+    , empty
+    , fromList
+    
+    -- * Insertion
+    , insert
+    , insertMany
+
+    -- * Info
+    , size
+    
+    -- * Extraction
+    , toList
+
+    -- * Lookups
+    , lookupId
+    , lookupKey
+    , lookupKeys
+    , unsafeLookupId
+    , unsafeLookupKey
+    , (!)
+
+    -- * Properties
+    , prop_hasId
+    , prop_stableId
+    , prop_keyRetrieval
+    , prop_keyRetrievalUnsafe
+    , prop_idempotent
+
+    ) where
+
+import Control.Applicative hiding (empty)
+import Control.DeepSeq
+import Data.Binary
+import Data.List (foldl')
+import Data.Hashable
+import Data.HashMap.Lazy (HashMap)
+import Data.Maybe
+import Data.Sequence (Seq, (|>))
+import Data.Serialize (Serialize)
+import qualified Data.HashMap.Lazy as H
+import qualified Data.Sequence as S
+import qualified Data.Serialize as C
+
+
+data Identifiers i a = Identifiers { ids   :: !(HashMap a i)
+                                   , names :: !(Seq a)
+                                   } deriving Eq
+
+instance Show a => Show (Identifiers i a) where
+    show s = "insertMany empty " ++ show (H.keys (ids s))
+
+instance (Binary i, Eq a, Hashable a, Binary a) => Binary (Identifiers i a) where
+    put s = put (H.toList $ ids s) >> put (names s)
+    get = Identifiers <$> (H.fromList <$> get) <*> get
+
+instance (Serialize i, Eq a, Hashable a, Serialize a) => Serialize (Identifiers i a) where
+    put s = C.put (H.toList $ ids s) >> C.put (names s)
+    get = Identifiers <$> (H.fromList <$> C.get) <*> C.get
+
+instance (NFData i, NFData a) => NFData (Identifiers i a) where
+    rnf (Identifiers i n) = rnf (i, n)
+
+-- | The empty Identifiers
+empty :: Identifiers i a
+empty = Identifiers H.empty S.empty
+
+-- | New Identifiers from list
+fromList :: (Integral i, Hashable a, Eq a) => [a] -> Identifiers i a
+fromList = insertMany empty
+
+-- | Insert item into set (given it a new id)
+insert :: (Integral i, Hashable a, Eq a) => Identifiers i a -> a -> Identifiers i a
+insert xs v = case H.lookup v (ids xs) of
+        Just _  -> xs
+        Nothing -> Identifiers (H.insert v next $ ids xs) (names xs |> v)
+    where next = fromIntegral $ S.length $ names xs
+
+-- | Insert many items into set
+insertMany :: (Integral i, Hashable a, Eq a) => Identifiers i a -> [a] -> Identifiers i a
+insertMany = foldl' insert
+
+-- | New List from Identifiers
+toList :: Identifiers i a -> [a]
+toList = H.keys . ids
+
+-- | Find id for given key
+lookupId :: (Hashable a, Eq a) => Identifiers i a -> a -> Maybe i
+lookupId = flip H.lookup . ids
+
+size :: Identifiers i a -> Int
+size = S.length . names
+
+unsafeLookupId :: (Hashable a, Eq a) => Identifiers i a -> a -> i
+unsafeLookupId = (H.!) . ids
+
+-- | Find key for given id
+lookupKey :: (Integral i) => Identifiers i a -> i -> Maybe a
+lookupKey ident x = let xs = names ident
+                    in if S.length xs < fromIntegral x
+                       then Nothing
+                       else Just $ unsafeLookupKey ident x
+
+-- | Given many ids, return many keys
+lookupKeys :: (Integral i) => Identifiers i a -> [i] -> [a]
+lookupKeys s = mapMaybe (lookupKey s)
+
+unsafeLookupKey :: Integral i => Identifiers i a -> i -> a
+unsafeLookupKey xs x = S.index (names xs) (fromIntegral x)
+
+(!) :: Integral i => Identifiers i a -> i -> a
+(!) = unsafeLookupKey
+
+-- | Items inserted are given ids
+prop_hasId :: String -> Bool
+prop_hasId x = isJust . lookupId (insert (empty :: Identifiers Int String) x) $ x
+
+-- | Inserted items have stable ids
+prop_stableId :: String -> Bool
+prop_stableId x = isJust a && a == b
+    where a = lookupId firstSet x
+          b = lookupId secondSet x
+          firstSet = insert (empty :: Identifiers Int String) x
+          secondSet = insert firstSet x
+
+-- | Given id can be used to fetch inserted item
+prop_keyRetrievalUnsafe :: [String] -> Bool
+prop_keyRetrievalUnsafe xs = all (\x -> ret x == x) xs
+    where ret = unsafeLookupKey s . unsafeLookupId s
+          s = insertMany (empty :: Identifiers Int String) xs
+
+-- | Given id can be used to fetch inserted item
+prop_keyRetrieval :: [String] -> Bool
+prop_keyRetrieval xs = all (\x -> ret x == Just (Just x)) xs
+    where ret x = lookupKey s <$> lookupId s x
+          s = insertMany (empty :: Identifiers Int String) xs
+
+-- | Inserting something more than once does not change the set
+prop_idempotent :: String -> Bool
+prop_idempotent x = insert (empty :: Identifiers Int String) x
+                        == insert (insert empty x) x
+
diff --git a/src/Data/TrieMap.hs b/src/Data/TrieMap.hs
--- a/src/Data/TrieMap.hs
+++ b/src/Data/TrieMap.hs
@@ -13,7 +13,6 @@
 
 data TrieNode k v = Node        !k    !(TrieNode k v) !(TrieNode k v)
                   | Vertical    !k    !(TrieNode k v)
-                  | Horizontal  !k                    !(TrieNode k v)
                   | ValueVert   !k !v !(TrieNode k v)
                   | ValueHoriz  !k !v                 !(TrieNode k v)
                   | ValueNode   !k !v !(TrieNode k v) !(TrieNode k v)
@@ -29,7 +28,6 @@
 instance (NFData k, NFData v) => NFData (TrieNode k v) where
     rnf (Node a b c)        = rnf (a, b, c)
     rnf (Vertical a b)      = rnf (a, b)
-    rnf (Horizontal a b)    = rnf (a, b)
     rnf (ValueVert a b c)   = rnf (a, b, c)
     rnf (ValueHoriz a b c)  = rnf (a, b, c)
     rnf (ValueNode a b c d) = rnf (a, b, c, d)
@@ -70,9 +68,6 @@
 lookupNode (Vertical k down) (x:xs)
     | null xs || x /= k = Nothing
     | otherwise         = lookupNode down xs
-lookupNode (Horizontal k right) ks@(x:_)
-    | x /= k            = Nothing
-    | otherwise         = lookupNode right ks
 lookupNode (ValueVert k v down) (x:xs)
     | null xs && x == k = Just v
     |            x == k = lookupNode down xs
@@ -109,10 +104,6 @@
     | null xs && x == k = ValueVert k v down
     |            x == k = Vertical k $ insertNode down xs v
     | otherwise         = Node k down $ createNode ks v
-insertNode (Horizontal k right) ks@(x:xs) v
-    | null xs && x == k = ValueHoriz k v right
-    |            x == k = Node k (createNode xs v) right
-    | otherwise         = Horizontal k $ insertNode right ks v
 insertNode (ValueVert k w down) ks@(x:xs) v
     | null xs && x == k = ValueVert k v down
     |            x == k = ValueVert k w $ insertNode down xs v
diff --git a/test/TestAll.hs b/test/TestAll.hs
--- a/test/TestAll.hs
+++ b/test/TestAll.hs
@@ -4,19 +4,19 @@
 import Test.Framework (defaultMain, testGroup, Test)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 
-import qualified Data.Identifiers as G
+import qualified Data.Identifiers.Hashable as H
 import qualified Data.Identifiers.ListLike as L
 
 main :: IO ()
 main = defaultMain tests
 
 tests :: [Test]
-tests = [ testGroup "QuickCheck Data.Identifiers"
-            [ testProperty "hasId"                G.prop_hasId
-            , testProperty "stableId"             G.prop_stableId
-            , testProperty "keyRetrieval"         G.prop_keyRetrieval
-            , testProperty "keyRetrievalUnsafe"   G.prop_keyRetrievalUnsafe
-            , testProperty "idempotent"           G.prop_idempotent
+tests = [ testGroup "QuickCheck Data.Identifiers.Hashable"
+            [ testProperty "hasId"                H.prop_hasId
+            , testProperty "stableId"             H.prop_stableId
+            , testProperty "keyRetrieval"         H.prop_keyRetrieval
+            , testProperty "keyRetrievalUnsafe"   H.prop_keyRetrievalUnsafe
+            , testProperty "idempotent"           H.prop_idempotent
             ]
         , testGroup "QuickCheck Data.Identifiers.ListLike"
             [ testProperty "hasId"                L.prop_hasId
