diff --git a/Data/Bijection/Class.hs b/Data/Bijection/Class.hs
--- a/Data/Bijection/Class.hs
+++ b/Data/Bijection/Class.hs
@@ -1,37 +1,110 @@
 
 module Data.Bijection.Class where
 
+import Control.Applicative ((<$>))
+import Control.DeepSeq
+import Data.Aeson
+import Data.Binary
+import Data.Serialize
+import Data.Tuple (swap)
+import GHC.Generics
+import Prelude (Bool,Maybe,map,($),Int, maybe, id, (.), seq, Read, Show, Eq, return)
+import Data.List (foldl')
 
 
-class Bijection z where
-  type ContL z :: *
-  type ContR z :: *
-  type ElemL z :: *
-  type ElemR z :: *
-  contL :: z -> ContL z
-  contR :: z -> ContR z
-  memberL :: z -> ElemL z -> Bool
-  memberL = (maybe False (const True) . ) . lookupL
-  memberR :: z -> ElemR z -> Bool
-  memberR = (maybe False (const True) . ) . lookupR
-  lookupL :: z -> ElemL z -> Maybe (ElemR z)
-  lookupR :: z -> ElemR z -> Maybe (ElemL z)
-  empty :: z
-  null :: z -> Bool
-  size :: z -> Int
-  fromList :: [(ElemL z, ElemR z)] -> z
-  toList :: z -> [(ElemL z, ElemR z)]
-  insert :: z -> (ElemL z, ElemR z) -> z
-  deleteByL :: z -> ElemL z -> z
-  deleteByR :: z -> ElemR z -> z
-  {-# INLINE memberL #-}
-  {-# INLINE memberR #-}
 
-findWithDefaultL :: Bijection z => ElemR z -> z -> ElemL z -> ElemR z
+-- | Bijection between finite sets.
+--
+-- Both data types are strict here.
+
+data Bimap l r = Bimap !l !r
+  deriving (Read,Show,Eq,Generic)
+
+class DomCod z where
+  type Dom z  :: *
+  type Cod z  :: *
+  member :: z -> Dom z -> Bool
+  lookup :: z -> Dom z -> Maybe (Cod z)
+  deleteDC :: z -> Dom z -> Maybe (Cod z, z)
+  insertDC :: z -> (Dom z,Cod z) -> z
+  toListDC :: z -> [(Dom z, Cod z)]
+  nullDC :: z -> Bool
+  emptyDC :: z
+  sizeDC :: z -> Int
+  fromListDC :: [(Dom z, Cod z)] -> z
+
+instance (NFData l, NFData r) => NFData (Bimap l r) where
+  rnf (Bimap l r) = rnf l `seq` rnf r `seq` ()
+
+instance (Binary l, Binary r) => Binary (Bimap l r)
+instance (Serialize l, Serialize r) => Serialize (Bimap l r)
+instance (DomCodCnt l r, ToJSON (Dom l), ToJSON (Dom r)) => ToJSON (Bimap l r) where
+  toJSON = toJSON . toList
+instance (DomCodCnt l r, FromJSON (Dom l), FromJSON (Dom r)) => FromJSON (Bimap l r) where
+  parseJSON j = fromList <$> parseJSON j
+
+type DomCodCnt l r = (DomCod l, DomCod r, Dom l ~ Cod r, Dom r ~ Cod l)
+
+
+
+contL :: Bimap l r -> l
+contL (Bimap l r) = l
+
+contR :: Bimap l r -> r
+contR (Bimap l r) = r
+
+memberL :: (DomCod l) => Bimap l r -> Dom l -> Bool
+memberL (Bimap l r) e = member l e
+
+memberR :: (DomCod r) => Bimap l r -> Dom r -> Bool
+memberR (Bimap l r) e = member r e
+
+lookupL :: (DomCod l) => Bimap l r -> Dom l -> Maybe (Cod l)
+lookupL (Bimap l r) k = lookup l k
+
+lookupR :: (DomCod r) => Bimap l r -> Dom r -> Maybe (Cod r)
+lookupR (Bimap l r) k = lookup r k
+
+empty :: (DomCodCnt l r) => Bimap l r
+empty = Bimap emptyDC emptyDC
+
+null :: DomCod l => Bimap l r -> Bool
+null (Bimap l r) = nullDC l
+
+size :: DomCod l => Bimap l r -> Int
+size (Bimap l r) = sizeDC l
+
+-- | Given a list of pairs @[(x,y)]@, turn it into a bimap @(x->y, y->x)@.
+
+fromList :: DomCodCnt l r => [(Dom l, Dom r)] -> Bimap l r
+fromList = foldl' insert empty
+
+toList :: DomCodCnt l r => Bimap l r -> [(Dom l, Dom r)]
+toList (Bimap l r) = toListDC l
+
+insert :: (DomCodCnt l r) => Bimap l r -> (Dom l, Cod l) -> Bimap l r
+insert (Bimap l r) (u,v) = Bimap (insertDC l (u,v)) (insertDC r (v,u))
+{-# Inline insert #-}
+
+deleteByL :: DomCodCnt l r => Bimap l r -> Dom l -> Bimap l r
+deleteByL b@(Bimap l r) k = maybe b id $ do
+  (k',l') <- deleteDC l k
+  (_ ,r') <- deleteDC r k'
+  return $ Bimap l' r'
+{-# Inline deleteByL #-}
+
+deleteByR :: DomCodCnt l r => Bimap l r -> Dom r -> Bimap l r
+deleteByR b@(Bimap l r) k = maybe b id $ do
+  (k',r') <- deleteDC r k
+  (_ ,l') <- deleteDC l k'
+  return $ Bimap l' r'
+{-# Inline deleteByR #-}
+
+findWithDefaultL :: DomCodCnt l r => Cod l -> Bimap l r -> Dom l -> Cod l
 findWithDefaultL def = (maybe def id . ) . lookupL
 {-# INLINE findWithDefaultL #-}
 
-findWithDefaultR :: Bijection z => ElemL z -> z -> ElemR z -> ElemL z
+findWithDefaultR :: DomCodCnt l r => Cod r -> Bimap l r -> Dom r -> Cod r
 findWithDefaultR def = (maybe def id . ) . lookupR
 {-# INLINE findWithDefaultR #-}
 
diff --git a/Data/Bijection/Hash.hs b/Data/Bijection/Hash.hs
deleted file mode 100644
--- a/Data/Bijection/Hash.hs
+++ /dev/null
@@ -1,58 +0,0 @@
-
-module Data.Bijection.Hash
-  ( module Data.Bijection.Class
-  , Bimap
-  ) where
-
-import           Control.DeepSeq
-import           Data.Aeson
-import           Data.Binary
-import           Data.Hashable (Hashable)
-import           Data.Serialize
-import           Data.Tuple (swap)
-import           GHC.Generics
-import qualified Data.HashMap.Strict as H
-
-import           Data.Bijection.Class
-
-
-
--- | A bijection between values of type @l@ and type @r@.
-
-newtype Bimap l r = Bimap (H.HashMap l r, H.HashMap r l)
-  deriving (Read,Show,Eq,Generic)
-
-instance (Eq l, Eq r, Hashable l, Hashable r) => Bijection (Bimap l r) where
-  type ContL (Bimap l r) = H.HashMap l r
-  type ContR (Bimap l r) = H.HashMap r l
-  type ElemL (Bimap l r) = l
-  type ElemR (Bimap l r) = r
-  contL (Bimap (l,r)) = l
-  contR (Bimap (l,r)) = r
-  lookupL (Bimap (l,r)) k = H.lookup k l
-  lookupR (Bimap (l,r)) k = H.lookup k r
-  empty = Bimap (H.empty, H.empty)
-  null (Bimap (l,_)) = H.null l
-  size (Bimap (l,_)) = H.size l
-  fromList xs = Bimap (H.fromList xs, H.fromList $ map swap xs)
-  toList (Bimap (l,_)) = H.toList l
-  insert (Bimap (l,r)) (x,y) = Bimap (H.insert x y l, H.insert y x r)
-  deleteByL (Bimap (l,r)) x =
-    let r' = maybe r (`H.delete` r) $ H.lookup x l
-        l' = H.delete x l
-    in  Bimap (l',r')
-  deleteByR (Bimap (l,r)) y =
-    let l' = maybe l (`H.delete` l) $ H.lookup y r
-        r' = H.delete y r
-    in  Bimap (l',r')
-  {-# INLINE lookupL #-}
-  {-# INLINE lookupR #-}
-
-instance (NFData l, NFData r) => NFData (Bimap l r) where
-  rnf (Bimap (l,r)) = rnf (l,r)
-
-instance (Binary (H.HashMap l r), Binary (H.HashMap r l)) => Binary (Bimap l r)
-instance (Ord l, Ord r, Serialize (H.HashMap l r), Serialize (H.HashMap r l)) => Serialize (Bimap l r)
-instance (ToJSON (H.HashMap l r), ToJSON (H.HashMap r l)) => ToJSON (Bimap l r)
-instance (FromJSON (H.HashMap l r), FromJSON (H.HashMap r l)) => FromJSON (Bimap l r)
-
diff --git a/Data/Bijection/HashMap.hs b/Data/Bijection/HashMap.hs
new file mode 100644
--- /dev/null
+++ b/Data/Bijection/HashMap.hs
@@ -0,0 +1,36 @@
+
+module Data.Bijection.HashMap
+  ( module Data.Bijection.Class
+  , H.HashMap
+  , BimapHashMap
+  ) where
+
+import           Control.Applicative ((<$>))
+import           Control.DeepSeq
+import           Data.Aeson
+import           Data.Binary
+import           Data.Hashable (Hashable)
+import           Data.Serialize
+import           Data.Tuple (swap)
+import           GHC.Generics
+import qualified Data.HashMap.Strict as H
+
+import           Data.Bijection.Class
+
+
+
+type BimapHashMap d c = Bimap (H.HashMap d c) (H.HashMap c d)
+
+instance (Eq d, Hashable d) => DomCod (H.HashMap d c) where
+  type Dom (H.HashMap d c) = d
+  type Cod (H.HashMap d c) = c
+  member h k = H.member k h
+  lookup h k = H.lookup k h
+  deleteDC h k = (,H.delete k h) <$> H.lookup k h
+  insertDC h (d,c) = H.insert d c h
+  toListDC = H.toList
+  nullDC = H.null
+  emptyDC = H.empty
+  sizeDC = H.size
+  fromListDC = H.fromList
+
diff --git a/Data/Bijection/Map.hs b/Data/Bijection/Map.hs
--- a/Data/Bijection/Map.hs
+++ b/Data/Bijection/Map.hs
@@ -3,9 +3,10 @@
 
 module Data.Bijection.Map
   ( module Data.Bijection.Class
-  , Bimap
+  , S.Map
   ) where
 
+import           Control.Applicative ((<$>))
 import           Control.DeepSeq
 import           Data.Aeson
 import           Data.Binary
@@ -18,43 +19,16 @@
 
 
 
--- | A bijection between values of type @l@ and type @r@, implemented via
--- strict maps.
-
-newtype Bimap l r = Bimap (S.Map l r, S.Map r l)
-  deriving (Read,Show,Eq,Generic)
-
-instance (Ord l, Ord r) => Bijection (Bimap l r) where
-  type ContL (Bimap l r) = S.Map l r
-  type ContR (Bimap l r) = S.Map r l
-  type ElemL (Bimap l r) = l
-  type ElemR (Bimap l r) = r
-  contL (Bimap (l,r)) = l
-  contR (Bimap (l,r)) = r
-  lookupL (Bimap (l,r)) k = S.lookup k l
-  lookupR (Bimap (l,r)) k = S.lookup k r
-  empty = Bimap (S.empty,S.empty)
-  null (Bimap (l,_)) = S.null l
-  size (Bimap (l,_)) = S.size l
-  fromList xs = Bimap (S.fromList xs, S.fromList $ map swap xs)
-  toList (Bimap (l,_)) = S.toList l
-  insert (Bimap (l,r)) (x,y) = Bimap (S.insert x y l, S.insert y x r)
-  deleteByL (Bimap (l,r)) x =
-    let r' = maybe r (`S.delete` r) $ S.lookup x l
-        l' = S.delete x l
-    in  Bimap (l',r')
-  deleteByR (Bimap (l,r)) y =
-    let l' = maybe l (`S.delete` l) $ S.lookup y r
-        r' = S.delete y r
-    in  Bimap (l',r')
-  {-# INLINE lookupL #-}
-  {-# INLINE lookupR #-}
-
-instance (NFData l, NFData r) => NFData (Bimap l r) where
-  rnf (Bimap (l,r)) = rnf (l,r)
-
-instance (Binary l, Binary r) => Binary (Bimap l r)
-instance (Ord l, Ord r, Serialize l, Serialize r) => Serialize (Bimap l r)
-instance (ToJSON (S.Map l r), ToJSON (S.Map r l)) => ToJSON (Bimap l r)
-instance (FromJSON (S.Map l r), FromJSON (S.Map r l)) => FromJSON (Bimap l r)
+instance (Eq d, Ord d) => DomCod (S.Map d c) where
+  type Dom (S.Map d c) = d
+  type Cod (S.Map d c) = c
+  member h k = S.member k h
+  lookup h k = S.lookup k h
+  deleteDC h k = (,S.delete k h) <$> S.lookup k h
+  insertDC h (d,c) = S.insert d c h
+  toListDC = S.toList
+  nullDC = S.null
+  emptyDC = S.empty
+  sizeDC = S.size
+  fromListDC = S.fromList
 
diff --git a/Data/Bijection/Vector.hs b/Data/Bijection/Vector.hs
--- a/Data/Bijection/Vector.hs
+++ b/Data/Bijection/Vector.hs
@@ -3,7 +3,7 @@
 
 module Data.Bijection.Vector
   ( module Data.Bijection.Class
-  , Bimap
+  , Vector
   ) where
 
 import           Control.Applicative ((<$>))
@@ -13,7 +13,7 @@
 import           Data.Serialize
 import           Data.Tuple (swap)
 import           Data.Vector.Binary
-import           Data.Vector.Cereal
+import           Data.Vector.Serialize
 import           Data.Vector (Vector)
 import           GHC.Generics
 import qualified Data.Vector.Generic as G
@@ -22,32 +22,21 @@
 
 
 
-newtype Bimap l r = Bimap (Vector (l,r))
-  deriving (Read,Show,Eq,Generic)
-
-instance (Eq l, Eq r) => Bijection (Bimap l r) where
-  type ContL (Bimap l r) = Vector (l,r)
-  type ContR (Bimap l r) = Vector (r,l)
-  type ElemL (Bimap l r) = l
-  type ElemR (Bimap l r) = r
-  contL (Bimap v) = v
-  contR (Bimap v) = G.map swap v
-  lookupL (Bimap v) k = snd <$> G.find ((==k) . fst) v
-  lookupR (Bimap v) k = fst <$> G.find ((==k) . snd) v
-  empty = Bimap G.empty
-  null (Bimap v) = G.null v
-  size (Bimap v) = G.length v
-  fromList = Bimap . G.fromList
-  toList (Bimap v) = G.toList v
-  insert (Bimap v) = Bimap . G.snoc v
-  deleteByL (Bimap v) x = Bimap $ G.filter ((/=x) . fst) v
-  deleteByR (Bimap v) y = Bimap $ G.filter ((/=y) . snd) v
-
-instance (NFData l, NFData r) => NFData (Bimap l r) where
-  rnf (Bimap v) = rnf v
-
-instance (Binary l, Binary r) => Binary (Bimap l r)
-instance (Serialize l, Serialize r) => Serialize (Bimap l r)
-instance (ToJSON l, ToJSON r) => ToJSON (Bimap l r)
-instance (FromJSON l, FromJSON r) => FromJSON (Bimap l r)
+instance DomCod (Vector c) where
+  type Dom (Vector c) = Int
+  type Cod (Vector c) = c
+  member v k = k >= 0 && k < G.length v
+  lookup v k = v G.!? k
+  deleteDC v k
+    | k+1 == G.length v = Just (v G.! k, G.init v)
+    | otherwise         = error "tried to delete non-last element"
+  insertDC v (d,c)
+    | d == G.length v          = G.snoc v c
+    | d >= 0 && d < G.length v = v G.// [(d,c)]
+    | otherwise                = error "tried to insert into non-contiguous range"
+  toListDC = G.toList . G.indexed
+  nullDC = G.null
+  emptyDC = G.empty
+  sizeDC = G.length
+  fromListDC = G.fromList . map snd
 
diff --git a/Data/Bijection/Vector/Storable.hs b/Data/Bijection/Vector/Storable.hs
--- a/Data/Bijection/Vector/Storable.hs
+++ b/Data/Bijection/Vector/Storable.hs
@@ -3,7 +3,7 @@
 
 module Data.Bijection.Vector.Storable
   ( module Data.Bijection.Class
-  , Bimap
+  , Vector
   ) where
 
 import           Control.Applicative ((<$>))
@@ -13,7 +13,7 @@
 import           Data.Serialize
 import           Data.Tuple (swap)
 import           Data.Vector.Binary
-import           Data.Vector.Cereal
+import           Data.Vector.Serialize
 import           Data.Vector.Storable (Vector, Storable)
 import           Foreign.Storable.Tuple
 import           GHC.Generics
@@ -22,33 +22,21 @@
 import           Data.Bijection.Class
 
 
-
-newtype Bimap l r = Bimap (Vector (l,r))
-  deriving (Read,Show,Eq,Generic)
-
-instance (Eq l, Eq r, Storable l, Storable r, Storable (l,r)) => Bijection (Bimap l r) where
-  type ContL (Bimap l r) = Vector (l,r)
-  type ContR (Bimap l r) = Vector (r,l)
-  type ElemL (Bimap l r) = l
-  type ElemR (Bimap l r) = r
-  contL (Bimap v) = v
-  contR (Bimap v) = G.map swap v
-  lookupL (Bimap v) k = snd <$> G.find ((==k) . fst) v
-  lookupR (Bimap v) k = fst <$> G.find ((==k) . snd) v
-  empty = Bimap G.empty
-  null (Bimap v) = G.null v
-  size (Bimap v) = G.length v
-  fromList = Bimap . G.fromList
-  toList (Bimap v) = G.toList v
-  insert (Bimap v) = Bimap . G.snoc v
-  deleteByL (Bimap v) x = Bimap $ G.filter ((/=x) . fst) v
-  deleteByR (Bimap v) y = Bimap $ G.filter ((/=y) . snd) v
-
-instance (NFData l, NFData r) => NFData (Bimap l r) where
-  rnf (Bimap v) = rnf v
-
-instance (Storable l, Storable r, Binary l, Binary r) => Binary (Bimap l r)
-instance (Storable l, Storable r, Serialize l, Serialize r) => Serialize (Bimap l r)
-instance (Storable l, Storable r, ToJSON l, ToJSON r) => ToJSON (Bimap l r)
-instance (Storable l, Storable r, FromJSON l, FromJSON r) => FromJSON (Bimap l r)
+instance (Storable c) => DomCod (Vector c) where
+  type Dom (Vector c) = Int
+  type Cod (Vector c) = c
+  member v k = k >= 0 && k < G.length v
+  lookup v k = v G.!? k
+  deleteDC v k
+    | k+1 == G.length v = Just (v G.! k, G.init v)
+    | otherwise         = error "tried to delete non-last element"
+  insertDC v (d,c)
+    | d == G.length v          = G.snoc v c
+    | d >= 0 && d < G.length v = v G.// [(d,c)]
+    | otherwise                = error "tried to insert into non-contiguous range"
+  toListDC = G.toList . G.indexed
+  nullDC = G.null
+  emptyDC = G.empty
+  sizeDC = G.length
+  fromListDC = G.fromList . map snd
 
diff --git a/Data/Bijection/Vector/Unboxed.hs b/Data/Bijection/Vector/Unboxed.hs
--- a/Data/Bijection/Vector/Unboxed.hs
+++ b/Data/Bijection/Vector/Unboxed.hs
@@ -3,7 +3,8 @@
 
 module Data.Bijection.Vector.Unboxed
   ( module Data.Bijection.Class
-  , Bimap
+  , Vector
+  , Bi
   ) where
 
 import           Control.Applicative ((<$>))
@@ -13,7 +14,7 @@
 import           Data.Serialize
 import           Data.Tuple (swap)
 import           Data.Vector.Binary
-import           Data.Vector.Cereal
+import           Data.Vector.Serialize
 import           Data.Vector.Unboxed (Vector, Unbox)
 import           GHC.Generics
 import qualified Data.Vector.Generic as G
@@ -22,34 +23,23 @@
 
 
 
-newtype Bimap l r = Bimap (Vector (l,r))
-  deriving (Read,Show,Eq,Generic)
-
-instance (Eq l, Eq r, Unbox l, Unbox r) => Bijection (Bimap l r) where
-  type ContL (Bimap l r) = Vector (l,r)
-  type ContR (Bimap l r) = Vector (r,l)
-  type ElemL (Bimap l r) = l
-  type ElemR (Bimap l r) = r
-  contL (Bimap v) = v
-  contR (Bimap v) = G.map swap v
-  lookupL (Bimap v) k = snd <$> G.find ((==k) . fst) v
-  lookupR (Bimap v) k = fst <$> G.find ((==k) . snd) v
-  empty = Bimap G.empty
-  null (Bimap v) = G.null v
-  size (Bimap v) = G.length v
-  fromList = Bimap . G.fromList
-  toList (Bimap v) = G.toList v
-  insert (Bimap v) = Bimap . G.snoc v
-  deleteByL (Bimap v) x = Bimap $ G.filter ((/=x) . fst) v
-  deleteByR (Bimap v) y = Bimap $ G.filter ((/=y) . snd) v
-  {-# INLINE lookupL #-}
-  {-# INLINE lookupR #-}
-
-instance (NFData l, NFData r) => NFData (Bimap l r) where
-  rnf (Bimap v) = rnf v
+type Bi d c = Bimap (Vector d) (Vector c)
 
-instance (Unbox l, Unbox r, Binary l, Binary r) => Binary (Bimap l r)
-instance (Unbox l, Unbox r, Serialize l, Serialize r) => Serialize (Bimap l r)
-instance (Unbox l, Unbox r, ToJSON l, ToJSON r) => ToJSON (Bimap l r)
-instance (Unbox l, Unbox r, FromJSON l, FromJSON r) => FromJSON (Bimap l r)
+instance (Unbox c) => DomCod (Vector c) where
+  type Dom (Vector c) = Int
+  type Cod (Vector c) = c
+  member v k = k >= 0 && k < G.length v
+  lookup v k = v G.!? k
+  deleteDC v k
+    | k+1 == G.length v = Just (v G.! k, G.init v)
+    | otherwise         = error "tried to delete non-last element"
+  insertDC v (d,c)
+    | d == G.length v          = G.snoc v c
+    | d >= 0 && d < G.length v = v G.// [(d,c)]
+    | otherwise                = error "tried to insert into non-contiguous range"
+  toListDC = G.toList . G.indexed
+  nullDC = G.null
+  emptyDC = G.empty
+  sizeDC = G.length
+  fromListDC = G.fromList . map snd
 
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Christian Hoener zu Siederdissen 2015
+Copyright Christian Hoener zu Siederdissen 2015-2016
 
 All rights reserved.
 
diff --git a/bimaps.cabal b/bimaps.cabal
--- a/bimaps.cabal
+++ b/bimaps.cabal
@@ -1,17 +1,17 @@
 Name:           bimaps
-Version:        0.0.0.4
+Version:        0.1.0.0
 License:        BSD3
 License-file:   LICENSE
 Author:         Christian Hoener zu Siederdissen
 Maintainer:     choener@bioinf.uni-leipzig.de
-Copyright:      Christian Hoener zu Siederdissen, 2014 - 2015
+Copyright:      Christian Hoener zu Siederdissen, 2014 - 2016
 homepage:       https://github.com/choener/bimaps
 bug-reports:    https://github.com/choener/bimaps/issues
 Stability:      Experimental
 Category:       Data
 Build-type:     Simple
 Cabal-version:  >= 1.10
-tested-with:    GHC == 7.8.4, GHC == 7.10.2
+tested-with:    GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1
 Synopsis:       bijections with multiple implementations.
 Description:
                 Bijections between sets of values.
@@ -27,34 +27,36 @@
 library
   exposed-modules:
     Data.Bijection.Class
-    Data.Bijection.Hash
+    Data.Bijection.HashMap
     Data.Bijection.Map
     Data.Bijection.Vector
     Data.Bijection.Vector.Unboxed
     Data.Bijection.Vector.Storable
 
-  -- 4.7.0.0 is ghc 7.8.1; 4.8.0.0 is ghc 7.10.1
-  build-depends: base                     >= 4.7      && < 4.9
-               , aeson                    >= 0.8      && < 0.11
-               , binary                   >= 0.7      && < 0.8
-               , cereal                   >= 0.4      && < 0.6
-               , containers               >= 0.5      && < 0.6
-               , deepseq                  >= 1.3      && < 1.5
-               , hashable                 >= 1.2      && < 1.3
-               , primitive                >= 0.5      && < 0.7
-               , storable-tuple           >= 0.0.2    && < 0.0.3
-               , unordered-containers     >= 0.2.5    && < 0.2.6
-               , vector                   >= 0.10     && < 0.12
-               , vector-binary-instances  >= 0.2      && < 0.3
-               , vector-th-unbox          >= 0.2      && < 0.3
+  build-depends: base                     >= 4.7      &&  < 5.0
+               , aeson                    >= 0.8      &&  < 0.12
+               , binary                   >= 0.7      &&  < 0.9
+               , cereal                   >= 0.4      &&  < 0.6
+               , cereal-vector            >= 0.2      &&  < 0.3
+               , containers               >= 0.5      &&  < 0.6
+               , deepseq                  >= 1.3      &&  < 1.5
+               , hashable                 >= 1.2      &&  < 1.3
+               , primitive                >= 0.5      &&  < 0.7
+               , storable-tuple           >= 0.0.3    &&  < 0.0.4
+               , unordered-containers     >= 0.2.5    &&  < 0.3.0
+               , vector                   >= 0.10     &&  < 0.12
+               , vector-binary-instances  >= 0.2      &&  < 0.3
+               , vector-th-unbox          >= 0.2      &&  < 0.3
   ghc-options:
     -O2
     -funbox-strict-fields
   default-language:
     Haskell2010
   default-extensions: BangPatterns
+                    , ConstraintKinds
                     , DeriveGeneric
                     , FlexibleContexts
+                    , TupleSections
                     , TypeFamilies
                     , UndecidableInstances
 
@@ -63,9 +65,11 @@
 benchmark BenchmarkBimaps
   build-depends: base
                , bimaps
-               , criterion   >= 1.0.2   && < 1.1.1
+               , containers
+               , criterion            >= 1.0.2  &&  < 1.2
                , deepseq
-               , mwc-random  >= 0.13    && < 0.14
+               , mwc-random           >= 0.13   &&  < 0.14
+               , unordered-containers
                , vector
   hs-source-dirs:
     tests
@@ -98,14 +102,16 @@
     tests
   default-language:
     Haskell2010
-  default-extensions: TemplateHaskell
+  default-extensions: BangPatterns
                     , ScopedTypeVariables
+                    , TemplateHaskell
+                    , TypeFamilies
   build-depends: base
                , bimaps
-               , QuickCheck                   >= 2.7  && < 2.9
-               , test-framework               >= 0.8  && < 0.9
-               , test-framework-quickcheck2   >= 0.3  && < 0.4
-               , test-framework-th            >= 0.2  && < 0.3
+               , QuickCheck                   >= 2.7  &&  < 2.9
+               , tasty                        >= 0.11
+               , tasty-quickcheck             >= 0.8
+               , tasty-th                     >= 0.1
 
 
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,4 +1,17 @@
+0.1.0.0
+-------
+
+- heterogeneous structures are now allowed
+- HashMap, Map, Vector (boxed, unboxed, storable) instances predefined
+
+0.0.1.0
+-------
+
+- use of vector-cereal for cereal instances
+- try the newest travis.yml from M. Snoyman
+
 0.0.0.4
+-------
 
 - stub properties
 
diff --git a/tests/Benchmark.hs b/tests/Benchmark.hs
--- a/tests/Benchmark.hs
+++ b/tests/Benchmark.hs
@@ -1,25 +1,37 @@
 
+--
+--
+-- TODO if 'benchLookup' has no explicit type, compilation fails under
+-- ghc-8.0.1. Investigate!
+
 module Main where
 
+import           Control.Applicative ((<$>))
+import           Control.DeepSeq
 import           Criterion.Main
-import qualified Data.Vector.Unboxed as VU
-import qualified Data.Vector.Generic as VG
-import qualified Data.Vector as VV
-import           Text.Printf
 import           Data.Tuple (swap)
-import           Control.Applicative ((<$>))
+import qualified Data.HashMap.Strict as H
+import qualified Data.Map.Strict as M
+import qualified Data.Vector as VV
+import qualified Data.Vector.Generic as VG
+import qualified Data.Vector.Storable as VS
+import qualified Data.Vector.Unboxed as VU
 import           System.Random.MWC
-import           Control.DeepSeq
+import           Text.Printf
 
+import qualified Data.Bijection.Class as B
+import qualified Data.Bijection.HashMap as HS
+import qualified Data.Bijection.Map as BM
 import qualified Data.Bijection.Vector as BV
-import qualified Data.Bijection.Vector.Unboxed as BU
 import qualified Data.Bijection.Vector.Storable as BS
-import qualified Data.Bijection.Map as BM
-import qualified Data.Bijection.Hash as HS
-import qualified Data.Bijection.Class as B
-
+import qualified Data.Bijection.Vector.Unboxed as BU
 
 
+runLookupBench
+  :: (BU.Dom r ~ BU.Dom l, BU.Cod r ~ BU.Cod l, BU.DomCod r,
+      BU.DomCod l, VG.Vector v (BU.Dom l), Ord (BU.Cod l),
+      Num (BU.Cod l)) =>
+     v (BU.Dom r) -> BU.Bimap l r -> Benchmark
 runLookupBench xs' z = bench s $ whnf allLR xs'
   where s = printf "%5d" (B.size z)
         lL k = B.lookupL z k
@@ -29,8 +41,13 @@
         allLR xs = allL xs + allR xs
         f k (Just (!x)) = max k x
         f k _           = k
-{-# INLINE runLookupBench #-}
+{-# Inline runLookupBench #-}
 
+benchLookup
+  :: (BU.Dom r ~ BU.Dom l, BU.Cod r ~ BU.Cod l, BU.DomCod r,
+      BU.DomCod l, VG.Vector v (BU.Dom l), Ord (BU.Cod l),
+      Num (BU.Cod l)) =>
+     v (BU.Dom r) -> BU.Bimap l r -> BU.Cod l
 benchLookup xs z = allLR -- bench s $ whnf allLR xs'
   where lL k = B.lookupL z k
         lR k = B.lookupR z k
@@ -39,13 +56,13 @@
         allLR = allL + allR
         f k (Just (!x)) = max k x
         f k _           = k
-{-# INLINE benchLookup #-}
+{-# Inline benchLookup #-}
 
-benchVU :: VU.Vector Int -> BU.Bimap Int Int -> Int
+benchVU :: VU.Vector Int -> BU.Bimap (VU.Vector Int) (VU.Vector Int) -> Int
 benchVU = benchLookup
 {-# NOINLINE benchVU #-}
 
-benchBM :: VU.Vector Int -> BM.Bimap Int Int -> Int
+benchBM :: VU.Vector Int -> BM.Bimap (M.Map Int Int) (M.Map Int Int) -> Int
 benchBM = benchLookup
 {-# NOINLINE benchBM #-}
 
@@ -53,11 +70,11 @@
 main = do
   lkup :: VU.Vector Int <- withSystemRandom . asGenIO $ \gen -> uniformVector gen 10
   inputs :: [[Int]] <- mapM (\l -> withSystemRandom . asGenIO $ \gen -> VU.toList <$> uniformVector gen l) [1, 5, 10, 50, 100, 1000] -- [1,10,100,1000,10000]
-  let zVV :: [BV.Bimap Int Int] = map (\i -> B.fromList $ zip i i) inputs
-  let zVU :: [BU.Bimap Int Int] = map (\i -> B.fromList $ zip i i) inputs
-  let zVS :: [BS.Bimap Int Int] = map (\i -> B.fromList $ zip i i) inputs
-  let zMS :: [BM.Bimap Int Int] = map (\i -> B.fromList $ zip i i) inputs
-  let zHS :: [HS.Bimap Int Int] = map (\i -> B.fromList $ zip i i) inputs
+  let zVV :: [BV.Bimap (VV.Vector Int) (VV.Vector Int)] = map (\i -> B.fromList $ zip i i) inputs
+  let zVU :: [BU.Bimap (VU.Vector Int) (VU.Vector Int)] = map (\i -> B.fromList $ zip i i) inputs
+  let zVS :: [BS.Bimap (VS.Vector Int) (VS.Vector Int)] = map (\i -> B.fromList $ zip i i) inputs
+  let zMS :: [BM.Bimap (M.Map Int Int) (M.Map Int Int)] = map (\i -> B.fromList $ zip i i) inputs
+  let zHS :: [HS.Bimap (H.HashMap Int Int) (H.HashMap Int Int)] = map (\i -> B.fromList $ zip i i) inputs
   deepseq (lkup,inputs,zVV,zVU,zVS,zMS,zHS) `seq` defaultMain
     [ bgroup "5"
       [ bench "vector/ unboxed" $ whnf (benchVU lkup) (zVU !! 1)
diff --git a/tests/properties.hs b/tests/properties.hs
--- a/tests/properties.hs
+++ b/tests/properties.hs
@@ -1,8 +1,60 @@
 
 module Main where
 
+import           Data.Function (on)
+import           Data.List (nubBy,sort)
+import           Test.QuickCheck
+import           Test.Tasty.QuickCheck (testProperty)
+import           Test.Tasty.TH
+import           Data.Proxy
 
+import           Data.Bijection.Class as BC
+import qualified Data.Bijection.HashMap as BH
+import qualified Data.Bijection.Vector.Unboxed as BVU
 
+
+
+-- * generic properties
+
+genericNonEmpty p (NonEmpty xs) = not $ BC.null bh
+  where ls = makeUnique xs
+        bh = fromList ls `asTypeOf` p
+
+genericSize p xs = length ls == size bh
+  where ls = makeUnique xs
+        bh = fromList ls `asTypeOf` p
+
+genericFromListToList p xs = ls == rs
+  where ls = sort $ makeUnique xs
+        bh = fromList ls `asTypeOf` p
+        rs = sort $ toList bh
+
+
+
+-- * Hashmaps
+
+bh = undefined :: BH.BimapHashMap Int Int
+
+prop_HashMap_nonEmpty = genericNonEmpty bh
+
+prop_HashMap_size = genericSize bh
+
+prop_HashMap_fromList_toList = genericFromListToList bh
+
+-- -- * unboxed vectors
+-- --
+-- -- TODO contiguous range needed
+-- 
+-- bvu = undefined :: BVU.Bi Int Int
+-- 
+-- prop_Vector_Unboxed_nonEmpty = genericNonEmpty bvu
+
+
+-- *
+
+makeUnique :: [(Int,Int)] -> [(Int,Int)]
+makeUnique = nubBy ((==) `on` snd) . nubBy ((==) `on` fst)
+
 main :: IO ()
-main = return ()
+main = $(defaultMainGenerator)
 
