diff --git a/avro.cabal b/avro.cabal
--- a/avro.cabal
+++ b/avro.cabal
@@ -1,7 +1,7 @@
 cabal-version: 1.12
 
 name:           avro
-version:        0.4.4.4
+version:        0.4.5.0
 synopsis:       Avro serialization support for Haskell
 description:    Avro serialization and deserialization support for Haskell
 category:       Data
@@ -33,6 +33,7 @@
     test/data/overlay/composite.avsc
     test/data/overlay/expectation.avsc
     test/data/overlay/primitives.avsc
+    test/data/fixed-types.avsc
 
 source-repository head
   type: git
@@ -64,6 +65,7 @@
       Data.Avro.DecodeRaw
       Data.Avro.Deconflict
       Data.Avro.Deriving
+      Data.Avro.Deriving.Lift
       Data.Avro.Deriving.NormSchema
       Data.Avro.EitherN
       Data.Avro.Encode
@@ -142,6 +144,7 @@
       Avro.JSONSpec
       Avro.NamespaceSpec
       Avro.NormSchemaSpec
+      Avro.ReuseFixedSpec
       Avro.SchemaSpec
       Avro.THEncodeContainerSpec
       Avro.THEnumSpec
diff --git a/src/Data/Avro/Decode/Lazy.hs b/src/Data/Avro/Decode/Lazy.hs
--- a/src/Data/Avro/Decode/Lazy.hs
+++ b/src/Data/Avro/Decode/Lazy.hs
@@ -318,16 +318,16 @@
         case runGetOrFail getLong bs of
           Left (bs', _, err) -> (bs', T.Error err)
           Right (bs', _, i)  ->
-            case symbolLookup i of
+            case symbols V.!? (fromIntegral i) of
               Nothing  -> (bs', T.Error ("Unknown value {" <> show i <> "} for enum " <> Text.unpack (typeName ty) ))
               Just sym -> (bs', T.Enum ty (fromIntegral i) sym)
 
-      Union ts unionLookup ->
+      Union ts ->
         case runGetOrFail getLong bs of
           Left (bs', _, err) -> (bs', T.Error err)
           Right (bs', _, i)  ->
-            case unionLookup i of
-              Nothing -> (bs', T.Error $ "Decoded Avro tag is outside the expected range for a Union. Tag: " <> show i <> " union of: " <> show (P.map typeName $ NE.toList ts))
+            case ts V.!? (fromIntegral i) of
+              Nothing -> (bs', T.Error $ "Decoded Avro tag is outside the expected range for a Union. Tag: " <> show i <> " union of: " <> show (V.map typeName ts))
               Just t  -> T.Union ts t <$> go t bs'
 
       Fixed {..} ->
diff --git a/src/Data/Avro/Decode/Lazy/Deconflict.hs b/src/Data/Avro/Decode/Lazy/Deconflict.hs
--- a/src/Data/Avro/Decode/Lazy/Deconflict.hs
+++ b/src/Data/Avro/Decode/Lazy/Deconflict.hs
@@ -19,6 +19,8 @@
 import           Data.Text                       (Text)
 import qualified Data.Text                       as Text
 import qualified Data.Text.Encoding              as Text
+import           Data.Vector                     (Vector)
+import qualified Data.Vector                     as V
 
 -- | @deconflict writer reader val@ will convert a value that was
 -- encoded/decoded with the writer's schema into the form specified by the
@@ -68,11 +70,11 @@
         | name a == name b && size a == size b = val
     go a@S.Record {} b@S.Record {} val
         | name a == name b = deconflictRecord a b val
-    go (S.Union xs _) (S.Union ys _) (T.Union _ tyVal val) =
+    go (S.Union xs) (S.Union ys) (T.Union _ tyVal val) =
         withSchemaIn tyVal xs $ \sch -> deconflictReaderUnion sch ys val
-    go nonUnion (S.Union ys _) val =
+    go nonUnion (S.Union ys) val =
         deconflictReaderUnion nonUnion ys val
-    go (S.Union xs _) nonUnion (T.Union _ tyVal val) =
+    go (S.Union xs) nonUnion (T.Union _ tyVal val) =
         withSchemaIn tyVal xs $ \sch -> deconflictValue sch nonUnion val
     go eTy dTy val =
       case val of
@@ -102,14 +104,14 @@
     Nothing    -> T.Error $ "Incorrect payload: union " <> (show . Foldable.toList $ typeName <$> schemas) <> " does not contain schema " <> Text.unpack (typeName schema)
     Just found -> f found
 
-deconflictReaderUnion :: Type -> NonEmpty Type -> T.LazyValue Type -> T.LazyValue Type
+deconflictReaderUnion :: Type -> Vector Type -> T.LazyValue Type -> T.LazyValue Type
 deconflictReaderUnion valueType unionTypes val =
   let hdl [] = T.Error $ "No corresponding union value for " <> Text.unpack (typeName valueType)
       hdl (d:rest) =
             case deconflictValue valueType d val of
               T.Error _ -> hdl rest
               v         -> T.Union unionTypes d v
-  in hdl (NE.toList unionTypes)
+  in hdl (V.toList unionTypes)
 
 deconflictRecord :: Type -> Type -> T.LazyValue Type -> T.LazyValue Type
 deconflictRecord writerSchema readerSchema (T.Record ty fldVals)  =
diff --git a/src/Data/Avro/Decode/Lazy/FromLazyAvro.hs b/src/Data/Avro/Decode/Lazy/FromLazyAvro.hs
--- a/src/Data/Avro/Decode/Lazy/FromLazyAvro.hs
+++ b/src/Data/Avro/Decode/Lazy/FromLazyAvro.hs
@@ -90,9 +90,11 @@
   fromLazyAvro v           = badValue v "Float"
 
 instance FromLazyAvro a => FromLazyAvro (Maybe a) where
-  fromLazyAvro (T.Union (S.Null :| [_])  _ T.Null) = pure Nothing
-  fromLazyAvro (T.Union (S.Null :| [_]) _ v)       = Just <$> fromLazyAvro v
-  fromLazyAvro v                                   = badValue v "Maybe a"
+  fromLazyAvro (T.Union ts _ v) = case (V.toList ts, v) of
+    ([S.Null, _], T.Null) -> pure Nothing
+    ([S.Null, _], v')     -> Just <$> fromLazyAvro v'
+    _                     -> badValue v "Maybe a"
+  fromLazyAvro v                = badValue v "Maybe a"
 
 instance FromLazyAvro a => FromLazyAvro [a] where
   fromLazyAvro (T.Array vec) = mapM fromLazyAvro $ toList vec
diff --git a/src/Data/Avro/Decode/Lazy/LazyValue.hs b/src/Data/Avro/Decode/Lazy/LazyValue.hs
--- a/src/Data/Avro/Decode/Lazy/LazyValue.hs
+++ b/src/Data/Avro/Decode/Lazy/LazyValue.hs
@@ -1,12 +1,12 @@
 module Data.Avro.Decode.Lazy.LazyValue
 where
 
-import           Data.ByteString
-import           Data.HashMap.Strict (HashMap)
-import           Data.Int
-import           Data.List.NonEmpty  (NonEmpty)
-import           Data.Text
-import           Data.Vector
+import Data.ByteString
+import Data.HashMap.Strict (HashMap)
+import Data.Int
+import Data.List.NonEmpty  (NonEmpty)
+import Data.Text
+import Data.Vector
 
 data LazyValue f
       = Null
@@ -17,11 +17,11 @@
       | Double Double
       | Bytes ByteString
       | String Text
-      | Array (Vector (LazyValue f))       -- ^ Dynamically enforced monomorphic type.
-      | Map (HashMap Text (LazyValue f))   -- ^ Dynamically enforced monomorphic type
-      | Record f (HashMap Text (LazyValue f)) -- Order and a map
-      | Union (NonEmpty f) f (LazyValue f) -- ^ Set of union options, schema for selected option, and the actual value.
+      | Array (Vector (LazyValue f))            -- ^ Dynamically enforced monomorphic type.
+      | Map (HashMap Text (LazyValue f))        -- ^ Dynamically enforced monomorphic type
+      | Record f (HashMap Text (LazyValue f))   -- ^ Order and a map
+      | Union (Vector f) f (LazyValue f)        -- ^ Set of union options, schema for selected option, and the actual value.
       | Fixed f ByteString
-      | Enum f Int Text  -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol
+      | Enum f Int Text                         -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol
       | Error !String
   deriving (Eq, Show)
diff --git a/src/Data/Avro/Decode/Strict/Internal.hs b/src/Data/Avro/Decode/Strict/Internal.hs
--- a/src/Data/Avro/Decode/Strict/Internal.hs
+++ b/src/Data/Avro/Decode/Strict/Internal.hs
@@ -67,13 +67,13 @@
       do let getField Field {..} = (fldName,) <$> go fldType
          T.Record ty . HashMap.fromList <$> mapM getField fields
     Enum {..} ->
-      do val <- getLong
-         let sym = fromMaybe "" (symbolLookup val) -- empty string for 'missing' symbols (alternative is an error or exception)
-         pure (T.Enum ty (fromIntegral val) sym)
-    Union ts unionLookup ->
       do i <- getLong
-         case unionLookup i of
-          Nothing -> fail $ "Decoded Avro tag is outside the expected range for a Union. Tag: " <> show i <> " union of: " <> show (P.map typeName $ NE.toList ts)
+         let sym = fromMaybe "" (symbols V.!? (fromIntegral i)) -- empty string for 'missing' symbols (alternative is an error or exception)
+         pure (T.Enum ty (fromIntegral i) sym)
+    Union ts ->
+      do i <- getLong
+         case ts V.!? (fromIntegral i) of
+          Nothing -> fail $ "Decoded Avro tag is outside the expected range for a Union. Tag: " <> show i <> " union of: " <> show (V.map typeName ts)
           Just t  -> T.Union ts t <$> go t
     Fixed {..} -> T.Fixed ty <$> G.getByteString (fromIntegral size)
 
diff --git a/src/Data/Avro/Deconflict.hs b/src/Data/Avro/Deconflict.hs
--- a/src/Data/Avro/Deconflict.hs
+++ b/src/Data/Avro/Deconflict.hs
@@ -19,6 +19,8 @@
 import           Data.Text           (Text)
 import qualified Data.Text           as Text
 import qualified Data.Text.Encoding  as Text
+import           Data.Vector         (Vector)
+import qualified Data.Vector         as V
 
 -- | @deconflict writer reader val@ will convert a value that was
 -- encoded/decoded with the writer's schema into the form specified by the
@@ -70,11 +72,11 @@
        | name a == name b && size a == size b = Right val
   go a@S.Record {} b@S.Record {} val
        | name a == name b = deconflictRecord a b val
-  go (S.Union xs _) (S.Union ys _) (T.Union _ tyVal val) =
+  go (S.Union xs) (S.Union ys) (T.Union _ tyVal val) =
        withSchemaIn tyVal xs $ \sch -> deconflictReaderUnion sch ys val
-  go nonUnion (S.Union ys _) val =
+  go nonUnion (S.Union ys) val =
        deconflictReaderUnion nonUnion ys val
-  go (S.Union xs _) nonUnion (T.Union _ tyVal val) =
+  go (S.Union xs) nonUnion (T.Union _ tyVal val) =
        withSchemaIn tyVal xs $ \sch -> deconflictValue sch nonUnion val
   go eTy dTy val =
     case val of
@@ -104,14 +106,14 @@
     Nothing    -> Left $ "Incorrect payload: union " <> (show . Foldable.toList $ typeName <$> schemas) <> " does not contain schema " <> Text.unpack (typeName schema)
     Just found -> f found
 
-deconflictReaderUnion :: Type -> NonEmpty Type -> T.Value Type -> Either String (T.Value Type)
+deconflictReaderUnion :: Type -> Vector Type -> T.Value Type -> Either String (T.Value Type)
 deconflictReaderUnion valueSchema unionTypes val =
     let hdl [] = Left "Impossible: empty non-empty list."
         hdl (d:rest) =
               case deconflictValue valueSchema d val of
                 Right v -> Right (T.Union unionTypes d v)
                 Left _  -> hdl rest
-    in hdl (NE.toList unionTypes)
+    in hdl (V.toList unionTypes)
 
 deconflictRecord :: Type -> Type -> T.Value Type -> Either String (T.Value Type)
 deconflictRecord writerSchema readerSchema (T.Record ty fldVals)  =
diff --git a/src/Data/Avro/Deriving.hs b/src/Data/Avro/Deriving.hs
--- a/src/Data/Avro/Deriving.hs
+++ b/src/Data/Avro/Deriving.hs
@@ -1,10 +1,10 @@
-{-# LANGUAGE CPP               #-}
-{-# LANGUAGE DeriveGeneric     #-}
-{-# LANGUAGE LambdaCase        #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE RecordWildCards   #-}
-{-# LANGUAGE TemplateHaskell   #-}
-{-# LANGUAGE ViewPatterns      #-}
+{-# LANGUAGE CPP                #-}
+{-# LANGUAGE DeriveGeneric      #-}
+{-# LANGUAGE LambdaCase         #-}
+{-# LANGUAGE OverloadedStrings  #-}
+{-# LANGUAGE RecordWildCards    #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell    #-}
 
 -- | This module lets us derive Haskell types from an Avro schema that
 -- can be serialized/deserialzed to Avro.
@@ -50,7 +50,6 @@
 import           Data.Semigroup     ((<>))
 import qualified Data.Text          as Text
 
-
 import GHC.Generics (Generic)
 
 import Language.Haskell.TH        as TH hiding (notStrict)
@@ -72,6 +71,9 @@
 import           Data.Avro.Decode.Lazy.FromLazyAvro
 import qualified Data.Avro.Decode.Lazy.LazyValue    as LV
 
+import Data.Avro.Deriving.Lift    ()
+import Language.Haskell.TH.Syntax (lift)
+
 -- | How to treat Avro namespaces in the generated Haskell types.
 data NamespaceBehavior =
     IgnoreNamespaces
@@ -312,7 +314,7 @@
 -- mySchema = $(makeSchema "schemas/my-schema.avsc")
 -- @
 makeSchema :: FilePath -> Q Exp
-makeSchema p = readSchema p >>= schemaDef'
+makeSchema p = readSchema p >>= lift
 
 makeSchemaFrom :: FilePath -> Text -> Q Exp
 makeSchemaFrom p name = do
@@ -320,7 +322,7 @@
 
   case subdefinition s name of
     Nothing -> fail $ "No such entity '" <> T.unpack name <> "' defined in " <> p
-    Just ss -> schemaDef' ss
+    Just ss -> lift ss
 
 readSchema :: FilePath -> Q Schema
 readSchema p = do
@@ -333,7 +335,7 @@
 ---------------------------- FromAvro -----------------------------------------
 
 genFromAvro :: NamespaceBehavior -> Schema -> Q [Dec]
-genFromAvro namespaceBehavior (S.Enum n _ _ _ _) =
+genFromAvro namespaceBehavior (S.Enum n _ _ _ ) =
   [d| instance FromAvro $(conT $ mkDataTypeName namespaceBehavior n) where
         fromAvro (AT.Enum _ i _) = $([| pure . toEnum|]) i
         fromAvro value           = $( [|\v -> badValue v $(mkTextLit $ S.renderFullname n)|] ) value
@@ -364,7 +366,7 @@
 
 -------------------------------- FromLazyAvro ---------------------------------
 genFromLazyAvro :: NamespaceBehavior -> Schema -> Q [Dec]
-genFromLazyAvro namespaceBehavior (S.Enum n _ _ _ _) =
+genFromLazyAvro namespaceBehavior (S.Enum n _ _ _) =
   [d| instance FromLazyAvro $(conT $ mkDataTypeName namespaceBehavior n) where
         fromLazyAvro (LV.Enum _ i _) = $([| pure . toEnum|]) i
         fromLazyAvro value           = $( [|\v -> badValue v $(mkTextLit $ S.renderFullname n)|] ) value
@@ -417,7 +419,7 @@
 ------------------------- ToAvro ----------------------------------------------
 
 genToAvro :: DeriveOptions -> Schema -> Q [Dec]
-genToAvro opts s@(S.Enum n _ _ vs _) =
+genToAvro opts s@(S.Enum n _ _ vs) =
   toAvroInstance (mkSchemaValueName (namespaceBehavior opts) n)
   where
     conP' = flip conP [] . mkAdtCtorName (namespaceBehavior opts) n
@@ -426,7 +428,7 @@
             toAvro = $([| \x ->
               let convert = AT.Enum $(varE sname) (fromEnum $([|x|]))
               in $(caseE [|x|] ((\v -> match (conP' v)
-                               (normalB [| convert (T.pack $(mkTextLit v))|]) []) <$> vs))
+                               (normalB [| convert (T.pack $(mkTextLit v))|]) []) <$> V.toList vs))
               |])
       |]
 genToAvro opts s@(S.Record n _ _ _ fs) =
@@ -460,91 +462,9 @@
 schemaDef sname sch = setName sname $
   [d|
       x :: Schema
-      x = $(schemaDef' sch)
+      x = sch -- $(schemaDef' sch)
   |]
 
-schemaDef' :: S.Type -> ExpQ
-schemaDef' = mkSchema
-  where mkSchema = \case
-          Null           -> [e| Null |]
-          Boolean        -> [e| Boolean |]
-          Int            -> [e| Int |]
-          Long           -> [e| Long |]
-          Float          -> [e| Float |]
-          Double         -> [e| Double |]
-          Bytes          -> [e| Bytes |]
-          String         -> [e| String |]
-          Array item     -> [e| Array $(mkSchema item) |]
-          Map values     -> [e| Map $(mkSchema values) |]
-          NamedType name -> [e| NamedType $(mkName name) |]
-          Record {..}    -> [e| Record { name      = $(mkName name)
-                                       , aliases   = $(ListE <$> mapM mkName aliases)
-                                       , doc       = $(mkMaybeText doc)
-                                       , order     = $(mkOrder order)
-                                       , fields    = $(ListE <$> mapM mkField fields)
-                                       }
-                              |]
-          Enum {..}      -> [e| mkEnum $(mkName name)
-                                       $(ListE <$> mapM mkName aliases)
-                                       $(mkMaybeText doc)
-                                       $(ListE <$> mapM mkText symbols)
-                              |]
-          Union {..}     -> [e| mkUnion $(mkNE options) |]
-          Fixed {..}     -> [e| Fixed { name      = $(mkName name)
-                                      , aliases   = $(ListE <$> mapM mkName aliases)
-                                      , size      = $(litE $ IntegerL $ fromIntegral size)
-                                      }
-                              |]
-
-        mkText text = [e| T.pack $(mkTextLit text) |]
-
-        mkName (TN name namespace) = [e| TN $(mkText name) $(mkNamespace namespace) |]
-        mkNamespace ls = listE $ stringE . T.unpack <$> ls
-
-        mkMaybeText (Just text) = [e| Just $(mkText text) |]
-        mkMaybeText Nothing     = [e| Nothing |]
-
-        mkOrder (Just Ascending)  = [e| Just Ascending |]
-        mkOrder (Just Descending) = [e| Just Descending |]
-        mkOrder (Just Ignore)     = [e| Just Ignore |]
-        mkOrder Nothing           = [e| Nothing |]
-
-        mkField Field {..} =
-          [e| Field { fldName    = $(mkText fldName)
-                    , fldAliases = $(ListE <$> mapM mkText fldAliases)
-                    , fldDoc     = $(mkMaybeText fldDoc)
-                    , fldOrder   = $(mkOrder fldOrder)
-                    , fldType    = $(mkSchema fldType)
-                    , fldDefault = $(fromMaybe [e|Nothing|] $ mkJust . mkDefaultValue <$> fldDefault)
-                    }
-            |]
-
-        mkJust exp = [e|Just $(exp)|]
-
-        mkDefaultValue = \case
-          AT.Null         -> [e| AT.Null |]
-          AT.Boolean b    -> [e| AT.Boolean $(if b then [e|True|] else [e|False|]) |]
-          AT.Int n        -> [e| AT.Int $(litE $ IntegerL $ fromIntegral n) |]
-          AT.Long n       -> [e| AT.Long $(litE $ IntegerL $ fromIntegral n) |]
-          AT.Float f      -> [e| AT.Long $(litE $ FloatPrimL $ realToFrac f) |]
-          AT.Double f     -> [e| AT.Long $(litE $ FloatPrimL $ realToFrac f) |]
-          AT.Bytes bs     -> [e| AT.Bytes $(mkByteString bs) |]
-          AT.String s     -> [e| AT.String $(mkText s) |]
-          AT.Array vec    -> [e| AT.Array $ V.fromList $(ListE <$> mapM mkDefaultValue (V.toList vec)) |]
-          AT.Map m        -> [e| AT.Map $ $(mkMap m) |]
-          AT.Record s m   -> [e| AT.Record $(mkSchema s) $(mkMap m) |]
-          AT.Union ts t v -> [e| AT.Union $(mkNE ts) $(mkSchema t) $(mkDefaultValue v) |]
-          AT.Fixed s bs   -> [e| AT.Fixed $(mkSchema s) $(mkByteString bs) |]
-          AT.Enum s n sym -> [e| AT.Enum $(mkSchema s) $(litE $ IntegerL $ fromIntegral n) $(mkText sym) |]
-
-        mkByteString bs = [e| B.pack $(ListE <$> mapM numericLit (B.unpack bs)) |]
-          where numericLit = litE . IntegerL . fromIntegral
-
-        mkMap (HM.toList -> xs) = [e| HM.fromList $(ListE <$> mapM mkKVPair xs) |]
-        mkKVPair (k, v)         = [e| ($(mkText k), $(mkDefaultValue v)) |]
-
-        mkNE (NE.toList -> xs) = [e| NE.fromList $(ListE <$> mapM mkSchema xs) |]
-
 -- | A hack around TemplateHaskell limitation:
 -- It is currently not possible to splice variable name in QQ.
 -- This function allows to replace hardcoded name into the specified one.
@@ -560,9 +480,9 @@
   flds <- traverse (mkField opts n) fs
   let dname = mkDataTypeName (namespaceBehavior opts) n
   sequenceA [genDataType dname flds]
-genType opts (S.Enum n _ _ vs _) = do
+genType opts (S.Enum n _ _ vs) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
-  sequenceA [genEnum dname (mkAdtCtorName (namespaceBehavior opts) n <$> vs)]
+  sequenceA [genEnum dname (mkAdtCtorName (namespaceBehavior opts) n <$> (V.toList vs))]
 genType opts (S.Fixed n _ s) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
   sequenceA [genNewtype dname]
@@ -577,23 +497,23 @@
   S.Double           -> [t| Double |]
   S.Bytes            -> [t| ByteString |]
   S.String           -> [t| Text |]
-  S.Union branches _ -> union branches
+  S.Union branches   -> union (V.toList branches)
   S.Record n _ _ _ _ -> [t| $(conT $ mkDataTypeName namespaceBehavior n) |]
   S.Map x            -> [t| Map Text $(go x) |]
   S.Array x          -> [t| [$(go x)] |]
   S.NamedType n      -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
   S.Fixed n _ _      -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
-  S.Enum n _ _ _ _   -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
+  S.Enum n _ _ _     -> [t| $(conT $ mkDataTypeName namespaceBehavior n)|]
   t                  -> error $ "Avro type is not supported: " <> show t
   where go = mkFieldTypeName namespaceBehavior
         union = \case
-          Null :| [x]       -> [t| Maybe $(go x) |]
-          x :| [Null]       -> [t| Maybe $(go x) |]
-          x :| [y]          -> [t| Either $(go x) $(go y) |]
-          a :| [b, c]       -> [t| Either3 $(go a) $(go b) $(go c) |]
-          a :| [b, c, d]    -> [t| Either4 $(go a) $(go b) $(go c) $(go d) |]
-          a :| [b, c, d, e] -> [t| Either5 $(go a) $(go b) $(go c) $(go d) $(go e) |]
-          _                 ->
+          [Null, x]       -> [t| Maybe $(go x) |]
+          [x, Null]       -> [t| Maybe $(go x) |]
+          [x, y]          -> [t| Either $(go x) $(go y) |]
+          [a, b, c]       -> [t| Either3 $(go a) $(go b) $(go c) |]
+          [a, b, c, d]    -> [t| Either4 $(go a) $(go b) $(go c) $(go d) |]
+          [a, b, c, d, e] -> [t| Either5 $(go a) $(go b) $(go c) $(go d) $(go e) |]
+          _               ->
             error "Unions with more than 5 elements are not yet supported"
 
 updateFirst :: (Text -> Text) -> Text -> Text
diff --git a/src/Data/Avro/Deriving/Lift.hs b/src/Data/Avro/Deriving/Lift.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Avro/Deriving/Lift.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE DeriveLift         #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell    #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Data.Avro.Deriving.Lift
+where
+
+import qualified Data.Avro.Schema           as Schema
+import qualified Data.Avro.Types.Value      as Avro
+import qualified Data.ByteString            as ByteString
+import qualified Data.HashMap.Strict        as HashMap
+import qualified Data.Text                  as Text
+import qualified Data.Vector                as Vector
+import           Language.Haskell.TH.Syntax (Lift (..))
+
+instance Lift ByteString.ByteString where
+  lift b = [| ByteString.pack $(lift $ ByteString.unpack b) |]
+
+instance Lift Text.Text where
+  lift t = [| Text.pack $(lift $ Text.unpack t) |]
+
+instance Lift a => Lift (Vector.Vector a) where
+  lift v = [| Vector.fromList $(lift $ Vector.toList v) |]
+
+instance (Lift k, Lift v) => Lift (HashMap.HashMap k v) where
+  lift m = [| HashMap.fromList $(lift $ HashMap.toList m) |]
+
+deriving instance Lift f => Lift (Avro.Value f)
+deriving instance Lift Schema.Field
+deriving instance Lift Schema.Order
+deriving instance Lift Schema.TypeName
+deriving instance Lift Schema.Type
diff --git a/src/Data/Avro/Deriving/NormSchema.hs b/src/Data/Avro/Deriving/NormSchema.hs
--- a/src/Data/Avro/Deriving/NormSchema.hs
+++ b/src/Data/Avro/Deriving/NormSchema.hs
@@ -14,6 +14,7 @@
 import qualified Data.Set                   as S
 import           Data.Text                  (Text)
 import qualified Data.Text                  as T
+import qualified Data.Vector                as V
 
 -- | Extracts all the records from the schema (flattens the schema)
 -- Named types get resolved when needed to include at least one "inlined"
@@ -31,7 +32,7 @@
 getTypes rec = case rec of
   r@Record{name, fields} -> (name,r) : (fields >>= (getTypes . fldType))
   Array t                -> getTypes t
-  Union (t1 :| ts) _     -> getTypes t1 <> concatMap getTypes ts
+  Union ts               -> concatMap getTypes (V.toList ts)
   Map t                  -> getTypes t
   e@Enum{name}           -> [(name, e)]
   f@Fixed{name}          -> [(name, f)]
@@ -54,13 +55,16 @@
       Nothing ->
         error $ "Unable to resolve schema: " <> show (typeName t)
 
-  Array s   -> Array <$> normSchema s
-  Map s     -> Map <$> normSchema s
-  Union l f -> flip Union f <$> traverse normSchema l
+  Array s -> Array <$> normSchema s
+  Map s   -> Map <$> normSchema s
+  Union l -> Union <$> traverse normSchema l
   r@Record{name = tn}  -> do
     modify' (M.insert tn (NamedType tn))
     flds <- mapM (\fld -> setType fld <$> normSchema (fldType fld)) (fields r)
     pure $ r { fields = flds }
+  r@Fixed{name = tn} -> do
+    modify' (M.insert tn (NamedType tn))
+    pure r
   s         -> pure s
   where
     setType fld t = fld { fldType = t}
diff --git a/src/Data/Avro/EitherN.hs b/src/Data/Avro/EitherN.hs
--- a/src/Data/Avro/EitherN.hs
+++ b/src/Data/Avro/EitherN.hs
@@ -214,27 +214,27 @@
 
 instance (ToAvro a, ToAvro b, ToAvro c) => ToAvro (Either3 a b c) where
   toAvro e =
-    let sch@(one :| [two, three]) = options (schemaOf e)
+    let sch = options (schemaOf e)
     in case e of
-      E3_1 a -> T.Union sch one   (toAvro a)
-      E3_2 b -> T.Union sch two   (toAvro b)
-      E3_3 c -> T.Union sch three (toAvro c)
+      E3_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E3_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E3_3 c -> T.Union sch (schemaOf c) (toAvro c)
 
 instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d) => ToAvro (Either4 a b c d) where
   toAvro e =
-    let sch@(one :| [two, three, four]) = options (schemaOf e)
+    let sch = options (schemaOf e)
     in case e of
-      E4_1 a -> T.Union sch one   (toAvro a)
-      E4_2 b -> T.Union sch two   (toAvro b)
-      E4_3 c -> T.Union sch three (toAvro c)
-      E4_4 d -> T.Union sch four  (toAvro d)
+      E4_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E4_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E4_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E4_4 d -> T.Union sch (schemaOf d) (toAvro d)
 
 instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e) => ToAvro (Either5 a b c d e) where
   toAvro e =
-    let sch@(one :| [two, three, four, five]) = options (schemaOf e)
+    let sch = options (schemaOf e)
     in case e of
-      E5_1 a -> T.Union sch one   (toAvro a)
-      E5_2 b -> T.Union sch two   (toAvro b)
-      E5_3 c -> T.Union sch three (toAvro c)
-      E5_4 d -> T.Union sch four  (toAvro d)
-      E5_5 e -> T.Union sch five  (toAvro e)
+      E5_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E5_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E5_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E5_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E5_5 e -> T.Union sch (schemaOf e) (toAvro e)
diff --git a/src/Data/Avro/Encode.hs b/src/Data/Avro/Encode.hs
--- a/src/Data/Avro/Encode.hs
+++ b/src/Data/Avro/Encode.hs
@@ -52,9 +52,9 @@
 import qualified Data.Vector                as V
 import qualified Data.Vector.Unboxed        as U
 import           Data.Word
+import           Prelude                    as P
 import           System.Random.TF.Init      (initTFGen)
 import           System.Random.TF.Instances (randoms)
-import           Prelude                    as P
 
 import Data.Avro.Codec
 import Data.Avro.EncodeRaw
@@ -295,8 +295,8 @@
             fs = P.map fldName (fields ty)
         in AvroM (bs, ty)
       T.Union opts sel val | F.length opts > 0 ->
-        case DL.elemIndex sel (NE.toList opts) of
-          Just idx -> AvroM (putI idx <> putAvro val, S.mkUnion opts)
+        case V.elemIndex sel opts of
+          Just idx -> AvroM (putI idx <> putAvro val, S.Union opts)
           Nothing  -> error "Union encoding specifies type not found in schema"
       T.Enum sch@S.Enum{..} ix t -> AvroM (putI ix, sch)
       T.Fixed ty bs  ->
diff --git a/src/Data/Avro/FromAvro.hs b/src/Data/Avro/FromAvro.hs
--- a/src/Data/Avro/FromAvro.hs
+++ b/src/Data/Avro/FromAvro.hs
@@ -84,9 +84,11 @@
   fromAvro v           = badValue v "Float"
 
 instance FromAvro a => FromAvro (Maybe a) where
-  fromAvro (T.Union (S.Null :| [_])  _ T.Null) = pure Nothing
-  fromAvro (T.Union (S.Null :| [_]) _ v)       = Just <$> fromAvro v
-  fromAvro v                                   = badValue v "Maybe a"
+  fromAvro (T.Union ts _ v) = case (V.toList ts, v) of
+    ([S.Null, _], T.Null) -> pure Nothing
+    ([S.Null, _], v')     -> Just <$> fromAvro v'
+    _                     -> badValue v "Maybe a"
+  fromAvro v                = badValue v "Maybe a"
 
 instance FromAvro a => FromAvro [a] where
   fromAvro (T.Array vec) = mapM fromAvro $ toList vec
diff --git a/src/Data/Avro/HasAvroSchema.hs b/src/Data/Avro/HasAvroSchema.hs
--- a/src/Data/Avro/HasAvroSchema.hs
+++ b/src/Data/Avro/HasAvroSchema.hs
@@ -84,7 +84,7 @@
   schema = Tagged S.Bytes
 
 instance (HasAvroSchema a, HasAvroSchema b) => HasAvroSchema (Either a b) where
-  schema = Tagged $ mkUnion (untag (schema :: Tagged a Type) :| [untag (schema :: Tagged b Type)])
+  schema = Tagged $ S.Union $ V.fromListN 2 [untag (schema :: Tagged a Type), untag (schema :: Tagged b Type)]
 
 instance (HasAvroSchema a) => HasAvroSchema (Map.Map Text a) where
   schema = wrapTag S.Map (schema :: Tagged a Type)
diff --git a/src/Data/Avro/JSON.hs b/src/Data/Avro/JSON.hs
--- a/src/Data/Avro/JSON.hs
+++ b/src/Data/Avro/JSON.hs
@@ -59,7 +59,7 @@
 -- @
 module Data.Avro.JSON where
 
-import           Data.Semigroup       ((<>))
+import Data.Semigroup ((<>))
 
 import qualified Data.Aeson           as Aeson
 import           Data.ByteString.Lazy (ByteString)
@@ -70,11 +70,12 @@
 import           Data.Tagged
 import qualified Data.Text            as Text
 
-import           Data.Avro            (FromAvro (..), Result (..), ToAvro (..))
-import qualified Data.Avro            as Avro
-import           Data.Avro.Schema     (Schema, parseAvroJSON)
-import qualified Data.Avro.Schema     as Schema
-import qualified Data.Avro.Types      as Avro
+import           Data.Avro        (FromAvro (..), Result (..), ToAvro (..))
+import qualified Data.Avro        as Avro
+import           Data.Avro.Schema (Schema, parseAvroJSON)
+import qualified Data.Avro.Schema as Schema
+import qualified Data.Avro.Types  as Avro
+import qualified Data.Vector      as V
 
 decodeAvroJSON :: Schema -> Aeson.Value -> Result (Avro.Value Schema)
 decodeAvroJSON schema json =
@@ -85,12 +86,12 @@
     missing name =
       fail ("Type " <> show name <> " not in schema")
 
-    union (Schema.Union schemas _) Aeson.Null
+    union (Schema.Union schemas) Aeson.Null
       | Schema.Null `elem` schemas =
           pure $ Avro.Union schemas Schema.Null Avro.Null
       | otherwise                  =
           fail "Null not in union."
-    union (Schema.Union schemas _) (Aeson.Object obj)
+    union (Schema.Union schemas) (Aeson.Object obj)
       | null obj =
           fail "Invalid encoding of union: empty object ({})."
       | length obj > 1 =
@@ -103,7 +104,7 @@
             branch =
               head $ HashMap.keys obj
             names =
-              HashMap.fromList [(Schema.typeName t, t) | t <- NE.toList schemas]
+              HashMap.fromList [(Schema.typeName t, t) | t <- V.toList schemas]
           in case HashMap.lookup (canonicalize branch) names of
             Just t  -> do
               nested <- parseAvroJSON union env t (obj ! branch)
diff --git a/src/Data/Avro/Schema.hs b/src/Data/Avro/Schema.hs
--- a/src/Data/Avro/Schema.hs
+++ b/src/Data/Avro/Schema.hs
@@ -8,7 +8,6 @@
 {-# LANGUAGE RecordWildCards       #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
 {-# LANGUAGE TupleSections         #-}
-{-# LANGUAGE TypeSynonymInstances  #-}
 {-# LANGUAGE ViewPatterns          #-}
 
 -- | Avro 'Schema's, represented here as values of type 'Schema',
@@ -83,8 +82,6 @@
 
 import GHC.Generics (Generic)
 
-import Text.Show.Functions ()
-
 -- | An Avro schema is either
 --
 -- * A "JSON object in the form @{"type":"typeName" ...}@
@@ -118,14 +115,12 @@
                , order   :: Maybe Order
                , fields  :: [Field]
                }
-      | Enum { name         :: TypeName
-             , aliases      :: [TypeName]
-             , doc          :: Maybe Text
-             , symbols      :: [Text]
-             , symbolLookup :: Int64 -> Maybe Text
+      | Enum { name    :: TypeName
+             , aliases :: [TypeName]
+             , doc     :: Maybe Text
+             , symbols :: V.Vector Text
              }
-      | Union { options     :: NonEmpty Type
-              , unionLookup :: Int64 -> Maybe Type
+      | Union { options     :: V.Vector Type
               }
       | Fixed { name    :: TypeName
               , aliases :: [TypeName]
@@ -149,9 +144,9 @@
 
   Record name1 _ _ _ fs1 == Record name2 _ _ _ fs2 =
     and [name1 == name2, fs1 == fs2]
-  Enum name1 _ _ s _ == Enum name2 _ _ s2 _ =
+  Enum name1 _ _ s == Enum name2 _ _ s2 =
     and [name1 == name2, s == s2]
-  Union a _ == Union b _ = a == b
+  Union a == Union b = a == b
   Fixed name1 _ s == Fixed name2 _ s2 =
     and [name1 == name2, s == s2]
 
@@ -167,16 +162,13 @@
        -> [Text]
           -- ^ The symbols of the enum.
        -> Type
-mkEnum name aliases doc symbols = Enum name aliases doc symbols lookup
- where lookup i = IM.lookup (fromIntegral i) table
-       table    = IM.fromList $ [0..] `zip` symbols
+mkEnum name aliases doc symbols = Enum name aliases doc (V.fromList symbols)
 
 -- | @mkUnion subTypes@ Defines a union of the provided subTypes.  N.B. it is
 -- invalid Avro to include another union or to have more than one of the same
 -- type as a direct member of the union.  No check is done for this condition!
 mkUnion :: NonEmpty Type -> Type
-mkUnion os = Union os (\i -> IM.lookup (fromIntegral i) mp)
- where mp = IM.fromList (zip [0..] $ NE.toList os)
+mkUnion  = Union . V.fromList . NE.toList
 
 -- | A named type in Avro has a name and, optionally, a namespace.
 --
@@ -302,7 +294,7 @@
     Array _        -> "array"
     Map   _        -> "map"
     NamedType name -> renderFullname name
-    Union (x:|_) _ -> typeName x
+    Union ts       -> typeName (V.head ts)
     _              -> renderFullname $ name bt
 
 data Field = Field { fldName    :: Text
@@ -343,7 +335,7 @@
     somename  -> return $ NamedType $ mkTypeName context somename Nothing
   A.Array arr
     | V.length arr > 0 ->
-      mkUnion . NE.fromList <$> mapM (parseSchemaJSON context) (V.toList arr)
+      Union <$> V.mapM (parseSchemaJSON context) arr
     | otherwise        -> fail "Unions must have at least one type."
   A.Object o -> do
     logicalType :: Maybe Text <- o .:? "logicalType"
@@ -573,8 +565,8 @@
                      -- ^ JSON encoding of an Avro value.
                   -> Result (Ty.Value Schema)
 parseFieldDefault env schema value = parseAvroJSON defaultUnion env schema value
-  where defaultUnion (Union ts@(t :| _) _) val = Ty.Union ts t <$> parseFieldDefault env t val
-        defaultUnion _ _                       = error "Impossible: not Union."
+  where defaultUnion (Union ts) val = Ty.Union ts (V.head ts) <$> parseFieldDefault env (V.head ts) val
+        defaultUnion _ _            = error "Impossible: not Union."
 
 -- | Parse JSON-encoded avro data.
 parseAvroJSON :: (Type -> A.Value -> Result (Ty.Value Type))
@@ -601,9 +593,9 @@
         case ty of
           String      -> return $ Ty.String s
           Enum {..}   ->
-              if s `elem` symbols
-                then return $ Ty.Enum ty (maybe (error "IMPOSSIBLE BUG") id $ lookup s (zip symbols [0..])) s
-                else fail $ "JSON string is not one of the expected symbols for enum '" <> show name <> "': " <> T.unpack s
+              case s `V.elemIndex` symbols of
+                Just i  -> pure $ Ty.Enum ty i s
+                Nothing -> fail $ "JSON string is not one of the expected symbols for enum '" <> show name <> "': " <> T.unpack s
           Bytes       -> Ty.Bytes <$> parseBytes s
           Fixed {..}  -> do
             bytes <- parseBytes s
@@ -726,7 +718,7 @@
       , and $ zipWith fieldMatches (fields a) (fields b)
       ]
   where fieldMatches = matches `on` fldType
-matches a@Union{} b@Union{}         = and $ NE.zipWith matches (options a) (options b)
+matches a@Union{} b@Union{}         = and $ V.zipWith matches (options a) (options b)
 matches t1 t2                       = t1 == t2
 
 -- | @extractBindings schema@ traverses a schema and builds a map of all declared
@@ -740,7 +732,7 @@
     let withRecord = HashMap.fromList $ (name : aliases) `zip` repeat t
     in HashMap.unions $ withRecord : (extractBindings . fldType <$> fields)
   e@Enum{..}   -> HashMap.fromList $ (name : aliases) `zip` repeat e
-  Union{..}    -> HashMap.unions $ NE.toList $ extractBindings <$> options
+  Union{..}    -> HashMap.unions $ V.toList $ extractBindings <$> options
   f@Fixed{..}  -> HashMap.fromList $ (name : aliases) `zip` repeat f
   Array{..}    -> extractBindings item
   Map{..}      -> extractBindings values
@@ -756,7 +748,7 @@
       t@(NamedType n)   -> fromMaybe t <$> gets (HashMap.lookup n)
       a@Array{item}     -> (\x -> a { item = x })   <$> go item
       m@Map{values}     -> (\x -> m { values = x }) <$> go values
-      u@Union{options}  -> mkUnion <$> traverse go options
+      u@Union{options}  -> Union <$> traverse go options
 
       r@Record{name, fields}  -> do
         fields' <- traverse expandField fields
@@ -775,7 +767,7 @@
     overlayType  a@Array{..}      = a { item    = overlayType item }
     overlayType  m@Map{..}        = m { values  = overlayType values }
     overlayType  r@Record{..}     = r { fields  = map overlayField fields }
-    overlayType  u@Union{..}      = mkUnion (NE.map overlayType options)
+    overlayType  u@Union{..}      = Union (V.map overlayType options)
     overlayType  nt@(NamedType _) = rebind nt
     overlayType  other            = other
 
diff --git a/src/Data/Avro/ToAvro.hs b/src/Data/Avro/ToAvro.hs
--- a/src/Data/Avro/ToAvro.hs
+++ b/src/Data/Avro/ToAvro.hs
@@ -1,27 +1,27 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE ConstraintKinds     #-}
+{-# LANGUAGE FlexibleInstances   #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Data.Avro.ToAvro
 
 where
 
-import           Control.Arrow        (first)
+import           Control.Arrow           (first)
 import           Data.Avro.HasAvroSchema
-import           Data.Avro.Schema     as S
-import           Data.Avro.Types      as T
-import qualified Data.ByteString      as B
-import           Data.ByteString.Lazy (ByteString)
-import qualified Data.ByteString.Lazy as BL
-import qualified Data.HashMap.Strict  as HashMap
+import           Data.Avro.Schema        as S
+import           Data.Avro.Types         as T
+import qualified Data.ByteString         as B
+import           Data.ByteString.Lazy    (ByteString)
+import qualified Data.ByteString.Lazy    as BL
+import qualified Data.HashMap.Strict     as HashMap
 import           Data.Int
-import           Data.List.NonEmpty (NonEmpty(..))
-import qualified Data.Map             as Map
-import           Data.Text            (Text)
-import qualified Data.Text            as Text
-import qualified Data.Text.Lazy       as TL
+import           Data.List.NonEmpty      (NonEmpty (..))
+import qualified Data.Map                as Map
 import           Data.Tagged
-import qualified Data.Vector          as V
-import qualified Data.Vector.Unboxed  as U
+import           Data.Text               (Text)
+import qualified Data.Text               as Text
+import qualified Data.Text.Lazy          as TL
+import qualified Data.Vector             as V
+import qualified Data.Vector.Unboxed     as U
 import           Data.Word
 
 class HasAvroSchema a => ToAvro a where
@@ -65,10 +65,10 @@
 
 instance (ToAvro a, ToAvro b) => ToAvro (Either a b) where
   toAvro e =
-    let sch@(l:|[r]) = options (schemaOf e)
+    let sch = options (schemaOf e)
     in case e of
-         Left a  -> T.Union sch l (toAvro a)
-         Right b -> T.Union sch r (toAvro b)
+         Left a  -> T.Union sch (schemaOf a) (toAvro a)
+         Right b -> T.Union sch (schemaOf b) (toAvro b)
 
 instance (ToAvro a) => ToAvro (Map.Map Text a) where
   toAvro = toAvro . HashMap.fromList . Map.toList
@@ -90,10 +90,10 @@
 
 instance (ToAvro a) => ToAvro (Maybe a) where
   toAvro a =
-    let sch@(l:|[r]) = options (schemaOf a)
+    let sch = options (schemaOf a)
     in case a of
       Nothing -> T.Union sch S.Null (toAvro ())
-      Just v  -> T.Union sch r (toAvro v)
+      Just v  -> T.Union sch (schemaOf v) (toAvro v)
 
 instance (ToAvro a) => ToAvro [a] where
   toAvro = T.Array . V.fromList . (toAvro <$>)
diff --git a/src/Data/Avro/Types/Value.hs b/src/Data/Avro/Types/Value.hs
--- a/src/Data/Avro/Types/Value.hs
+++ b/src/Data/Avro/Types/Value.hs
@@ -2,16 +2,16 @@
 {-# LANGUAGE DeriveGeneric  #-}
 module Data.Avro.Types.Value where
 
-import           Control.DeepSeq     (NFData)
+import Control.DeepSeq (NFData)
 
-import           Data.ByteString
-import           Data.HashMap.Strict (HashMap)
-import           Data.Int
-import           Data.List.NonEmpty  (NonEmpty)
-import           Data.Text
-import           Data.Vector
+import Data.ByteString
+import Data.HashMap.Strict (HashMap)
+import Data.Int
+import Data.List.NonEmpty  (NonEmpty)
+import Data.Text
+import Data.Vector
 
-import           GHC.Generics        (Generic)
+import GHC.Generics (Generic)
 
 data Value f
       = Null
@@ -25,7 +25,7 @@
       | Array (Vector (Value f))       -- ^ Dynamically enforced monomorphic type.
       | Map (HashMap Text (Value f))   -- ^ Dynamically enforced monomorphic type
       | Record f (HashMap Text (Value f)) -- Order and a map
-      | Union (NonEmpty f) f (Value f) -- ^ Set of union options, schema for selected option, and the actual value.
+      | Union (Vector f) f (Value f) -- ^ Set of union options, schema for selected option, and the actual value.
       | Fixed f {-# UNPACK #-} !ByteString
       | Enum f {-# UNPACK #-} !Int Text  -- ^ An enum is a set of the possible symbols (the schema) and the selected symbol
   deriving (Eq, Show, Generic, NFData)
diff --git a/test/Avro/DefaultsSpec.hs b/test/Avro/DefaultsSpec.hs
--- a/test/Avro/DefaultsSpec.hs
+++ b/test/Avro/DefaultsSpec.hs
@@ -14,7 +14,7 @@
 import           Data.List.NonEmpty  (NonEmpty (..))
 import qualified Data.Vector         as V
 
-import           Test.Hspec
+import Test.Hspec
 
 {-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
 
@@ -35,7 +35,7 @@
       msgSchema = schemaOf (undefined :: MaybeTest)
       fixedSchema = schemaOf (undefined :: FixedTag)
       defaults = fldDefault <$> fields msgSchema
-    in defaults `shouldBe` [ Just $ Ty.Union (Null :| [String]) Null Ty.Null
+    in defaults `shouldBe` [ Just $ Ty.Union (V.fromList [Null, String]) Null Ty.Null
                            , Just $ Ty.Fixed fixedSchema "\0\42\255"
                            , Just $ Ty.Bytes "\0\37\255"
                            ]
diff --git a/test/Avro/ReuseFixedSpec.hs b/test/Avro/ReuseFixedSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Avro/ReuseFixedSpec.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell     #-}
+module Avro.ReuseFixedSpec
+where
+
+import qualified Data.Aeson           as Aeson
+import           Data.Avro            as Avro
+import           Data.Avro.Deriving
+import           Data.Avro.Schema     (Type (..), fields, fldType, mkUnion)
+import           Data.ByteString.Lazy as LBS
+import           Data.List.NonEmpty   (NonEmpty (..))
+import qualified Data.Set             as S
+
+import Test.Hspec
+
+deriveAvro "test/data/fixed-types.avsc"
+
+spec :: Spec
+spec = describe "Avro.ReuseFixedSpec" $ do
+  it "should generate sensible schema" $ do
+    let msg = ReuseFixed (FixedData "ABCDEFGHIJKLMNOP") (FixedData "PONMLKJIHGFEDCBA")
+    Avro.decode(Avro.encode(msg)) `shouldBe` Success msg
+
diff --git a/test/Avro/THUnionSpec.hs b/test/Avro/THUnionSpec.hs
--- a/test/Avro/THUnionSpec.hs
+++ b/test/Avro/THUnionSpec.hs
@@ -5,7 +5,7 @@
 module Avro.THUnionSpec
 where
 
-import qualified Data.List.NonEmpty   as NE
+import qualified Data.List.NonEmpty as NE
 
 import qualified Data.Aeson           as Aeson
 import           Data.Avro
@@ -15,12 +15,13 @@
 import qualified Data.Avro.Types      as Avro
 import qualified Data.ByteString.Lazy as LBS
 import qualified Data.Map             as Map
+import qualified Data.Vector          as V
 
-import           System.Directory     (doesFileExist)
+import System.Directory (doesFileExist)
 
-import           Test.Hspec
+import Test.Hspec
 
-import           Paths_avro
+import Paths_avro
 
 deriveAvro "test/data/unions.avsc"
 
@@ -67,8 +68,8 @@
         , field "four"  (Schema.mkUnion (NE.fromList [Schema.Int, Schema.String, Schema.Long, foo]))         Nothing
         , field "five"  (Schema.mkUnion (NE.fromList [Schema.Int, Schema.String, Schema.Long, foo, notFoo])) Nothing
         ]
-      scalarsDefault  = Just $ Avro.Union (NE.fromList [Schema.String, Schema.Long]) Schema.String (Avro.String "foo")
-      nullableDefault = Just $ Avro.Union (NE.fromList [Schema.Null, Schema.Int])    Schema.Null   Avro.Null
+      scalarsDefault  = Just $ Avro.Union (V.fromList [Schema.String, Schema.Long]) Schema.String (Avro.String "foo")
+      nullableDefault = Just $ Avro.Union (V.fromList [Schema.Null, Schema.Int])    Schema.Null   Avro.Null
 
       fooSchema = record "haskell.avro.example.Foo" [field "stuff" Schema.String Nothing]
       barSchema = record "haskell.avro.example.Bar"
diff --git a/test/data/fixed-types.avsc b/test/data/fixed-types.avsc
new file mode 100644
--- /dev/null
+++ b/test/data/fixed-types.avsc
@@ -0,0 +1,18 @@
+{
+  "name": "ReuseFixed",
+  "type": "record",
+  "fields": [
+    {
+      "name": "primary",
+      "type": {
+        "type": "fixed",
+        "name": "FixedData",
+        "size": 16
+      }
+    },
+    {
+      "name": "secondary",
+      "type": "FixedData"
+    }
+  ]
+}
