diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
 # Native Haskell implementation of Avro
 
+[![CircleCI](https://circleci.com/gh/haskell-works/avro.svg?style=svg)](https://circleci.com/gh/haskell-works/avro)
+[![Hackage](https://img.shields.io/hackage/v/avro.svg?logo=haskell)](https://hackage.haskell.org/package/avro)
+
 This is a Haskell [Avro](https://avro.apache.org/) library useful for decoding
 and encoding Avro data structures.  Avro can be thought of as a serialization
 format and RPC specification which induces three separable tasks:
@@ -26,6 +29,7 @@
 | ByteString        | "bytes"                         |
 | Maybe a           | ["null", "a"]                   |
 | Either a b        | ["a", "b"]                      |
+| Identity a        | ["a"]                           |
 | Map Text a        | {"type": "map", "value": "a"}   |
 | Map String a      | {"type": "map", "value": "a"}   |
 | HashMap Text a    | {"type": "map", "value": "a"}   |
diff --git a/avro.cabal b/avro.cabal
--- a/avro.cabal
+++ b/avro.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.2
 
 name:                   avro
-version:                0.4.6.0
+version:                0.4.7.0
 synopsis:               Avro serialization support for Haskell
 description:            Avro serialization and deserialization support for Haskell
 category:               Data
@@ -55,6 +55,7 @@
 common avro                     { build-depends: avro                                               }
 common base16-bytestring        { build-depends: base16-bytestring                                  }
 common bifunctors               { build-depends: bifunctors                                         }
+common big-decimal              { build-depends: HasBigDecimal                                      }
 common binary                   { build-depends: binary                                             }
 common bytestring               { build-depends: bytestring                                         }
 common containers               { build-depends: containers                                         }
@@ -78,9 +79,11 @@
 common semigroups               { build-depends: semigroups                                         }
 common tagged                   { build-depends: tagged                                             }
 common text                     { build-depends: text                     >= 1.2.3      && < 1.3    }
+common time                     { build-depends: time                                               }
 common tf-random                { build-depends: tf-random                                          }
 common transformers             { build-depends: transformers                                       }
 common unordered-containers     { build-depends: unordered-containers                               }
+common uuid                     { build-depends: uuid                                               }
 common vector                   { build-depends: vector                                             }
 common zlib                     { build-depends: zlib                                               }
 
@@ -98,6 +101,7 @@
                       , array
                       , base16-bytestring
                       , bifunctors
+                      , big-decimal
                       , binary
                       , bytestring
                       , containers
@@ -111,8 +115,10 @@
                       , semigroups
                       , tagged
                       , text
+                      , time
                       , tf-random
                       , unordered-containers
+                      , uuid
                       , vector
                       , zlib
   exposed-modules:      Data.Avro
@@ -140,9 +146,11 @@
                         Data.Avro.Schema
                         Data.Avro.ToAvro
                         Data.Avro.Types
+                        Data.Avro.Types.Decimal
                         Data.Avro.Types.Value
                         Data.Avro.Zag
                         Data.Avro.Zig
+  other-modules:        Data.Avro.Types.Time
   hs-source-dirs:       src
   other-extensions:     OverloadedStrings
 
@@ -153,6 +161,7 @@
                       , avro
                       , base16-bytestring
                       , bifunctors
+                      , big-decimal
                       , binary
                       , bytestring
                       , containers
@@ -172,8 +181,10 @@
                       , tagged
                       , text
                       , tf-random
+                      , time
                       , transformers
                       , unordered-containers
+                      , uuid
                       , vector
   type:                 exitcode-stdio-1.0
   ghc-options:          -threaded
diff --git a/bench/Bench/Time.hs b/bench/Bench/Time.hs
--- a/bench/Bench/Time.hs
+++ b/bench/Bench/Time.hs
@@ -61,8 +61,8 @@
           ]
         recordSchema = Schema.Record "Rec" [] Nothing Nothing
           [ Schema.Field "b" [] Nothing Nothing Schema.Boolean Nothing
-          , Schema.Field "i" [] Nothing Nothing Schema.Int Nothing
-          , Schema.Field "l" [] Nothing Nothing Schema.Long Nothing
+          , Schema.Field "i" [] Nothing Nothing Schema.Int' Nothing
+          , Schema.Field "l" [] Nothing Nothing Schema.Long' Nothing
           ]
 
 encodeAvro :: Value Schema -> LBS.ByteString
@@ -79,9 +79,9 @@
   [ bench "bools" $
       nf (decodeAvro $ Schema.Array Schema.Boolean) bools
   , bench "ints" $
-      nf (decodeAvro $ Schema.Array Schema.Int) ints
+      nf (decodeAvro $ Schema.Array Schema.Int') ints
   , bench "longs" $
-      nf (decodeAvro $ Schema.Array Schema.Long) longs
+      nf (decodeAvro $ Schema.Array Schema.Long') longs
   , bench "records" $
       nf (decodeAvro $ Schema.Array recordSchema) records
   ]
@@ -107,8 +107,8 @@
           ]
         recordSchema = Schema.Record "Rec" [] Nothing Nothing
           [ Schema.Field "b" [] Nothing Nothing Schema.Boolean Nothing
-          , Schema.Field "i" [] Nothing Nothing Schema.Int Nothing
-          , Schema.Field "l" [] Nothing Nothing Schema.Long Nothing
+          , Schema.Field "i" [] Nothing Nothing Schema.Int' Nothing
+          , Schema.Field "l" [] Nothing Nothing Schema.Long' Nothing
           ]
 
 decodeAvro :: Schema -> LBS.ByteString -> Value Schema
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
@@ -294,16 +294,16 @@
   go :: Schema -> BL.ByteString -> (BL.ByteString, T.LazyValue Schema)
   go ty bs =
     case ty of
-      Null    -> (bs, T.Null)
-      Boolean -> decodeGet T.Boolean  bs
-      Int     -> decodeGet T.Int      bs
-      Long    -> decodeGet T.Long     bs
-      Float   -> decodeGet T.Float    bs
-      Double  -> decodeGet T.Double   bs
-      Bytes   -> decodeGet T.Bytes    bs
-      String  -> decodeGet T.String   bs
-      Array t -> T.Array . V.fromList . mconcat <$> getElements bs (go t)
-      Map t   -> T.Map . HashMap.fromList . mconcat <$> getKVPairs bs (go t)
+      Null     -> (bs, T.Null)
+      Boolean  -> decodeGet T.Boolean  bs
+      Int _    -> decodeGet T.Int      bs
+      Long _   -> decodeGet T.Long     bs
+      Float    -> decodeGet T.Float    bs
+      Double   -> decodeGet T.Double   bs
+      Bytes _  -> decodeGet T.Bytes    bs
+      String _ -> decodeGet T.String   bs
+      Array t  -> T.Array . V.fromList . mconcat <$> getElements bs (go t)
+      Map t    -> T.Map . HashMap.fromList . mconcat <$> getKVPairs bs (go t)
       NamedType tn ->
         case runGetOrFail (env tn) bs of
           Left (bs', _, err) -> (bs', T.Error err)
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
@@ -78,15 +78,15 @@
         withSchemaIn tyVal xs $ \sch -> deconflictValue sch nonUnion val
     go eTy dTy val =
       case val of
-        T.Int i32  | dTy == S.Long   -> T.Long   (fromIntegral i32)
-                   | dTy == S.Float  -> T.Float  (fromIntegral i32)
-                   | dTy == S.Double -> T.Double (fromIntegral i32)
-        T.Long i64 | dTy == S.Float  -> T.Float (fromIntegral i64)
-                   | dTy == S.Double -> T.Double (fromIntegral i64)
-        T.Float f  | dTy == S.Double -> T.Double (realToFrac f)
-        T.String s | dTy == S.Bytes  -> T.Bytes (Text.encodeUtf8 s)
-        T.Bytes bs | dTy == S.String -> T.String (Text.decodeUtf8 bs)
-        _                            -> T.Error $ "Can not resolve differing writer and reader schemas: " ++ show (eTy, dTy)
+        T.Int i32  | S.Long _ <- dTy   -> T.Long   (fromIntegral i32)
+                   | dTy == S.Float    -> T.Float  (fromIntegral i32)
+                   | dTy == S.Double   -> T.Double (fromIntegral i32)
+        T.Long i64 | dTy == S.Float    -> T.Float (fromIntegral i64)
+                   | dTy == S.Double   -> T.Double (fromIntegral i64)
+        T.Float f  | dTy == S.Double   -> T.Double (realToFrac f)
+        T.String s | S.Bytes _ <- dTy  -> T.Bytes (Text.encodeUtf8 s)
+        T.Bytes bs | S.String _ <- dTy -> T.String (Text.decodeUtf8 bs)
+        _                              -> T.Error $ "Can not resolve differing writer and reader schemas: " ++ show (eTy, dTy)
 
 -- The writer's symbol must be present in the reader's enum
 deconflictEnum :: Schema -> Schema -> T.LazyValue Schema -> T.LazyValue Schema
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
@@ -6,11 +6,14 @@
 
 where
 
+import           Control.Monad.Identity          (Identity(..))
 import           Control.Arrow                   (first)
 import           Data.Avro.Decode.Lazy.LazyValue as T
 import qualified Data.Avro.Encode                as E
 import           Data.Avro.HasAvroSchema
 import           Data.Avro.Schema                as S
+import           Data.Avro.Types.Decimal         as D
+import           Data.Avro.Types.Time
 import qualified Data.ByteString                 as B
 import           Data.ByteString.Lazy            (ByteString)
 import qualified Data.ByteString.Lazy            as BL
@@ -24,9 +27,12 @@
 import           Data.Text                       (Text)
 import qualified Data.Text                       as Text
 import qualified Data.Text.Lazy                  as TL
+import qualified Data.Time                       as Time
+import qualified Data.UUID                       as UUID
 import qualified Data.Vector                     as V
 import qualified Data.Vector.Unboxed             as U
 import           Data.Word
+import           GHC.TypeLits
 
 -- |  'FromLazyAvro' is a clone of 'FromAvro' except that
 -- it works for lazy values ('LazyValue').
@@ -44,6 +50,13 @@
     Nothing -> fail $ "Requested field not available: " <> show key
     Just v  -> fromLazyAvro v
 
+instance (FromLazyAvro a) => FromLazyAvro (Identity a) where
+  fromLazyAvro e@(T.Union _ branch x)
+    | S.matches branch sch = Identity  <$> fromLazyAvro x
+    | otherwise            = badValue e "Identity"
+    where Tagged sch = schema :: Tagged a Schema
+  fromLazyAvro x = badValue x "Identity"
+
 instance (FromLazyAvro a, FromLazyAvro b) => FromLazyAvro (Either a b) where
   fromLazyAvro e@(T.Union _ branch x)
     | S.matches branch schemaA = Left  <$> fromLazyAvro x
@@ -88,6 +101,28 @@
 instance FromLazyAvro Float where
   fromLazyAvro (T.Float f) = pure f
   fromLazyAvro v           = badValue v "Float"
+
+instance (KnownNat p, KnownNat s) => FromLazyAvro (D.Decimal p s) where
+  fromLazyAvro (T.Long n) = pure $ D.fromUnderlyingValue $ fromIntegral n
+  fromLazyAvro (T.Int  n) = pure $ D.fromUnderlyingValue $ fromIntegral n
+  fromLazyAvro v          = badValue v "Decimal"
+
+instance FromLazyAvro UUID.UUID where
+  fromLazyAvro v@(T.String s)
+    = case UUID.fromText s of
+        Nothing -> badValue v "UUID"
+        Just u  -> pure u
+  fromLazyAvro v = badValue v "UUID"
+
+instance FromLazyAvro Time.Day where
+  fromLazyAvro (T.Int  v) = pure $ fromDaysSinceEpoch (toInteger v)
+  fromLazyAvro (T.Long v) = pure $ fromDaysSinceEpoch (toInteger v)
+  fromLazyAvro v = badValue v "Date"
+
+instance FromLazyAvro Time.DiffTime where
+  fromLazyAvro (T.Int  v) = pure $ microsToDiffTime (toInteger v)
+  fromLazyAvro (T.Long v) = pure $ microsToDiffTime (toInteger v)
+  fromLazyAvro v = badValue v "TimeMicros"
 
 instance FromLazyAvro a => FromLazyAvro (Maybe a) where
   fromLazyAvro (T.Union ts _ v) = case (V.toList ts, v) of
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
@@ -48,18 +48,18 @@
  go :: Schema -> Get (T.Value Schema)
  go ty =
   case ty of
-    Null    -> return T.Null
-    Boolean -> T.Boolean <$> getAvro
-    Int     -> T.Int     <$> getAvro
-    Long    -> T.Long    <$> getAvro
-    Float   -> T.Float   <$> getAvro
-    Double  -> T.Double  <$> getAvro
-    Bytes   -> T.Bytes   <$> getAvro
-    String  -> T.String  <$> getAvro
-    Array t ->
+    Null     -> return T.Null
+    Boolean  -> T.Boolean <$> getAvro
+    Int _    -> T.Int     <$> getAvro
+    Long _   -> T.Long    <$> getAvro
+    Float    -> T.Float   <$> getAvro
+    Double   -> T.Double  <$> getAvro
+    Bytes _  -> T.Bytes   <$> getAvro
+    String _ -> T.String  <$> getAvro
+    Array t  ->
       do vals <- getBlocksOf t
          return $ T.Array (V.fromList $ mconcat vals)
-    Map  t  ->
+    Map  t   ->
       do kvs <- getKVBlocks t
          return $ T.Map (HashMap.fromList $ mconcat kvs)
     NamedType tn -> env tn >>= go
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
@@ -80,15 +80,15 @@
        withSchemaIn tyVal xs $ \sch -> deconflictValue sch nonUnion val
   go eTy dTy val =
     case val of
-      T.Int i32  | dTy == S.Long   -> Right $ T.Long   (fromIntegral i32)
-                 | dTy == S.Float  -> Right $ T.Float  (fromIntegral i32)
-                 | dTy == S.Double -> Right $ T.Double (fromIntegral i32)
-      T.Long i64 | dTy == S.Float  -> Right $ T.Float (fromIntegral i64)
-                 | dTy == S.Double -> Right $ T.Double (fromIntegral i64)
-      T.Float f  | dTy == S.Double -> Right $ T.Double (realToFrac f)
-      T.String s | dTy == S.Bytes  -> Right $ T.Bytes (Text.encodeUtf8 s)
-      T.Bytes bs | dTy == S.String -> Right $ T.String (Text.decodeUtf8 bs)
-      _                            -> Left $ "Can not resolve differing writer and reader schemas: " ++ show (eTy, dTy)
+      T.Int i32  | S.Long _ <- dTy   -> Right $ T.Long   (fromIntegral i32)
+                 | dTy == S.Float    -> Right $ T.Float  (fromIntegral i32)
+                 | dTy == S.Double   -> Right $ T.Double (fromIntegral i32)
+      T.Long i64 | dTy == S.Float    -> Right $ T.Float (fromIntegral i64)
+                 | dTy == S.Double   -> Right $ T.Double (fromIntegral i64)
+      T.Float f  | dTy == S.Double   -> Right $ T.Double (realToFrac f)
+      T.String s | S.Bytes _ <- dTy  -> Right $ T.Bytes (Text.encodeUtf8 s)
+      T.Bytes bs | S.String _ <- dTy -> Right $ T.String (Text.decodeUtf8 bs)
+      _                              -> Left $ "Can not resolve differing writer and reader schemas: " ++ show (eTy, dTy)
 
 -- The writer's symbol must be present in the reader's enum
 deconflictEnum :: Schema -> Schema -> T.Value Schema -> Either String (T.Value Schema)
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
@@ -33,15 +33,16 @@
 )
 where
 
-import           Control.Monad      (join)
-import           Data.Aeson         (eitherDecode)
-import qualified Data.Aeson         as J
-import           Data.Avro          hiding (decode, encode)
-import           Data.Avro.Schema   as S
-import qualified Data.Avro.Types    as AT
-import           Data.ByteString    (ByteString)
-import qualified Data.ByteString    as B
-import           Data.Char          (isAlphaNum)
+import           Control.Monad          (join)
+import           Control.Monad.Identity (Identity)
+import           Data.Aeson             (eitherDecode)
+import qualified Data.Aeson             as J
+import           Data.Avro              hiding (decode, encode)
+import           Data.Avro.Schema       as S
+import qualified Data.Avro.Types        as AT
+import           Data.ByteString        (ByteString)
+import qualified Data.ByteString        as B
+import           Data.Char              (isAlphaNum)
 import           Data.Int
 import           Data.List.NonEmpty (NonEmpty ((:|)))
 import qualified Data.List.NonEmpty as NE
@@ -49,6 +50,8 @@
 import           Data.Maybe         (fromMaybe)
 import           Data.Semigroup     ((<>))
 import qualified Data.Text          as Text
+import           Data.Time          (Day, DiffTime)
+import           Data.UUID          (UUID)
 
 import GHC.Generics (Generic)
 
@@ -175,8 +178,8 @@
       case S.fldType field of
         S.Null    -> True
         S.Boolean -> True
-        S.Int     -> True
-        S.Long    -> True
+        S.Int _   -> True
+        S.Long _  -> True
         S.Float   -> True
         S.Double  -> True
         _         -> False
@@ -346,7 +349,7 @@
            $(genFromAvroFieldsExp (mkDataTypeName namespaceBehavior n) fs) r
         fromAvro value           = $( [|\v -> badValue v $(mkTextLit $ S.renderFullname n)|] ) value
   |]
-genFromAvro namespaceBehavior (S.Fixed n _ s) =
+genFromAvro namespaceBehavior (S.Fixed n _ s _) =
   [d| instance FromAvro $(conT $ mkDataTypeName namespaceBehavior n) where
         fromAvro (AT.Fixed _ v)
           | BS.length v == s = pure $ $(conE (mkDataTypeName namespaceBehavior n)) v
@@ -377,7 +380,7 @@
            $(genFromLazyAvroFieldsExp (mkDataTypeName namespaceBehavior n) fs) r
         fromLazyAvro value           = $( [|\v -> badValue v $(mkTextLit $ S.renderFullname n)|] ) value
   |]
-genFromLazyAvro namespaceBehavior (S.Fixed n _ s) =
+genFromLazyAvro namespaceBehavior (S.Fixed n _ s _) =
   [d| instance FromLazyAvro $(conT $ mkDataTypeName namespaceBehavior n) where
         fromLazyAvro (LV.Fixed _ v)
           | BS.length v == s = pure $ $(conE (mkDataTypeName namespaceBehavior n)) v
@@ -448,7 +451,7 @@
                 )
             |]
 
-genToAvro opts s@(S.Fixed n _ size) =
+genToAvro opts s@(S.Fixed n _ size _) =
   toAvroInstance (mkSchemaValueName (namespaceBehavior opts) n)
   where
     toAvroInstance sname =
@@ -483,7 +486,7 @@
 genType opts (S.Enum n _ _ vs) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
   sequenceA [genEnum dname (mkAdtCtorName (namespaceBehavior opts) n <$> (V.toList vs))]
-genType opts (S.Fixed n _ s) = do
+genType opts (S.Fixed n _ s _) = do
   let dname = mkDataTypeName (namespaceBehavior opts) n
   sequenceA [genNewtype dname]
 genType _ _ = pure []
@@ -491,30 +494,44 @@
 mkFieldTypeName :: NamespaceBehavior -> S.Schema -> Q TH.Type
 mkFieldTypeName namespaceBehavior = \case
   S.Boolean          -> [t| Bool |]
-  S.Long             -> [t| Int64 |]
-  S.Int              -> [t| Int32 |]
+  S.Long (Just (DecimalL (Decimal p s)))
+                     -> [t| Decimal $(litT $ numTyLit p) $(litT $ numTyLit s) |]
+  S.Long (Just TimeMicros)
+                     -> [t| DiffTime |]
+  S.Long _           -> [t| Int64 |]
+  S.Int (Just Date)  -> [t| Day |]
+  S.Int _            -> [t| Int32 |]
   S.Float            -> [t| Float |]
   S.Double           -> [t| Double |]
-  S.Bytes            -> [t| ByteString |]
-  S.String           -> [t| Text |]
+  S.Bytes _          -> [t| ByteString |]
+  S.String Nothing   -> [t| Text |]
+  S.String (Just UUID) -> [t| UUID |]
   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.Fixed 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
+          []              ->
+            error "Empty union types are not supported"
+          [x]             -> [t| Identity $(go x) |]
           [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"
+          [a, b, c, d, e, f] -> [t| Either6 $(go a) $(go b) $(go c) $(go d) $(go e) $(go f) |]
+          [a, b, c, d, e, f, g] -> [t| Either7 $(go a) $(go b) $(go c) $(go d) $(go e) $(go f) $(go g)|]
+          [a, b, c, d, e, f, g, h] -> [t| Either8 $(go a) $(go b) $(go c) $(go d) $(go e) $(go f) $(go g) $(go h)|]
+          [a, b, c, d, e, f, g, h, i] -> [t| Either9 $(go a) $(go b) $(go c) $(go d) $(go e) $(go f) $(go g) $(go h) $(go i)|]
+          [a, b, c, d, e, f, g, h, i, j] -> [t| Either10 $(go a) $(go b) $(go c) $(go d) $(go e) $(go f) $(go g) $(go h) $(go i) $(go j)|]
+          ls              ->
+            error $ "Unions with more than 10 elements are not yet supported: Union has " <> (show . length) ls <> " elements"
 
 updateFirst :: (Text -> Text) -> Text -> Text
 updateFirst f t =
diff --git a/src/Data/Avro/Deriving/Lift.hs b/src/Data/Avro/Deriving/Lift.hs
--- a/src/Data/Avro/Deriving/Lift.hs
+++ b/src/Data/Avro/Deriving/Lift.hs
@@ -34,4 +34,10 @@
 deriving instance Lift Schema.Field
 deriving instance Lift Schema.Order
 deriving instance Lift Schema.TypeName
+deriving instance Lift Schema.Decimal
+deriving instance Lift Schema.LogicalTypeBytes
+deriving instance Lift Schema.LogicalTypeFixed
+deriving instance Lift Schema.LogicalTypeInt
+deriving instance Lift Schema.LogicalTypeLong
+deriving instance Lift Schema.LogicalTypeString
 deriving instance Lift Schema.Schema
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
@@ -23,6 +23,16 @@
 
 data Either5 a b c d e = E5_1 a | E5_2 b | E5_3 c | E5_4 d | E5_5 e deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
 
+data Either6 a b c d e f = E6_1 a | E6_2 b | E6_3 c | E6_4 d | E6_5 e | E6_6 f deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
+
+data Either7 a b c d e f g = E7_1 a | E7_2 b | E7_3 c | E7_4 d | E7_5 e | E7_6 f | E7_7 g deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
+
+data Either8 a b c d e f g h = E8_1 a | E8_2 b | E8_3 c | E8_4 d | E8_5 e | E8_6 f | E8_7 g | E8_8 h deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
+
+data Either9 a b c d e f g h i = E9_1 a | E9_2 b | E9_3 c | E9_4 d | E9_5 e | E9_6 f | E9_7 g | E9_8 h | E9_9 i deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
+
+data Either10 a b c d e f g h i j = E10_1 a | E10_2 b | E10_3 c | E10_4 d | E10_5 e | E10_6 f | E10_7 g | E10_8 h | E10_9 i | E10_10 j deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)
+
 instance Applicative (Either3 a b) where
   pure = E3_3
   E3_1 a <*> _ = E3_1 a
@@ -44,6 +54,61 @@
   E5_4 a <*> _ = E5_4 a
   E5_5 f <*> r = fmap f r
 
+instance Applicative (Either6 a b c d e) where
+  pure = E6_6
+  E6_1 a <*> _ = E6_1 a
+  E6_2 a <*> _ = E6_2 a
+  E6_3 a <*> _ = E6_3 a
+  E6_4 a <*> _ = E6_4 a
+  E6_5 a <*> _ = E6_5 a
+  E6_6 f <*> r = fmap f r
+
+instance Applicative (Either7 a b c d e f) where
+  pure = E7_7
+  E7_1 a <*> _ = E7_1 a
+  E7_2 a <*> _ = E7_2 a
+  E7_3 a <*> _ = E7_3 a
+  E7_4 a <*> _ = E7_4 a
+  E7_5 a <*> _ = E7_5 a
+  E7_6 a <*> _ = E7_6 a
+  E7_7 f <*> r = fmap f r
+
+instance Applicative (Either8 a b c d e f g) where
+  pure = E8_8
+  E8_1 a <*> _ = E8_1 a
+  E8_2 a <*> _ = E8_2 a
+  E8_3 a <*> _ = E8_3 a
+  E8_4 a <*> _ = E8_4 a
+  E8_5 a <*> _ = E8_5 a
+  E8_6 a <*> _ = E8_6 a
+  E8_7 a <*> _ = E8_7 a
+  E8_8 f <*> r = fmap f r
+
+instance Applicative (Either9 a b c d e f g h) where
+  pure = E9_9
+  E9_1 a <*> _ = E9_1 a
+  E9_2 a <*> _ = E9_2 a
+  E9_3 a <*> _ = E9_3 a
+  E9_4 a <*> _ = E9_4 a
+  E9_5 a <*> _ = E9_5 a
+  E9_6 a <*> _ = E9_6 a
+  E9_7 a <*> _ = E9_7 a
+  E9_8 a <*> _ = E9_8 a
+  E9_9 f <*> r = fmap f r
+
+instance Applicative (Either10 a b c d e f g h i) where
+  pure = E10_10
+  E10_1 a <*> _ = E10_1 a
+  E10_2 a <*> _ = E10_2 a
+  E10_3 a <*> _ = E10_3 a
+  E10_4 a <*> _ = E10_4 a
+  E10_5 a <*> _ = E10_5 a
+  E10_6 a <*> _ = E10_6 a
+  E10_7 a <*> _ = E10_7 a
+  E10_8 a <*> _ = E10_8 a
+  E10_9 a <*> _ = E10_9 a
+  E10_10 f <*> r = fmap f r
+
 instance Bifunctor (Either3 a) where
   bimap _ _ (E3_1 a) = E3_1 a
   bimap f _ (E3_2 a) = E3_2 (f a)
@@ -62,6 +127,56 @@
   bimap f _ (E5_4 a) = E5_4 (f a)
   bimap _ g (E5_5 a) = E5_5 (g a)
 
+instance Bifunctor (Either6 a b c d) where
+  bimap _ _ (E6_1 a) = E6_1 a
+  bimap _ _ (E6_2 a) = E6_2 a
+  bimap _ _ (E6_3 a) = E6_3 a
+  bimap _ _ (E6_4 a) = E6_4 a
+  bimap f _ (E6_5 a) = E6_5 (f a)
+  bimap _ g (E6_6 a) = E6_6 (g a)
+
+instance Bifunctor (Either7 a b c d e) where
+  bimap _ _ (E7_1 a) = E7_1 a
+  bimap _ _ (E7_2 a) = E7_2 a
+  bimap _ _ (E7_3 a) = E7_3 a
+  bimap _ _ (E7_4 a) = E7_4 a
+  bimap _ _ (E7_5 a) = E7_5 a
+  bimap f _ (E7_6 a) = E7_6 (f a)
+  bimap _ g (E7_7 a) = E7_7 (g a)
+
+instance Bifunctor (Either8 a b c d e f) where
+  bimap _ _ (E8_1 a) = E8_1 a
+  bimap _ _ (E8_2 a) = E8_2 a
+  bimap _ _ (E8_3 a) = E8_3 a
+  bimap _ _ (E8_4 a) = E8_4 a
+  bimap _ _ (E8_5 a) = E8_5 a
+  bimap _ _ (E8_6 a) = E8_6 a
+  bimap f _ (E8_7 a) = E8_7 (f a)
+  bimap _ g (E8_8 a) = E8_8 (g a)
+
+instance Bifunctor (Either9 a b c d e f g) where
+  bimap _ _ (E9_1 a) = E9_1 a
+  bimap _ _ (E9_2 a) = E9_2 a
+  bimap _ _ (E9_3 a) = E9_3 a
+  bimap _ _ (E9_4 a) = E9_4 a
+  bimap _ _ (E9_5 a) = E9_5 a
+  bimap _ _ (E9_6 a) = E9_6 a
+  bimap _ _ (E9_7 a) = E9_7 a
+  bimap f _ (E9_8 a) = E9_8 (f a)
+  bimap _ g (E9_9 a) = E9_9 (g a)
+
+instance Bifunctor (Either10 a b c d e f g h) where
+  bimap _ _ (E10_1 a) = E10_1 a
+  bimap _ _ (E10_2 a) = E10_2 a
+  bimap _ _ (E10_3 a) = E10_3 a
+  bimap _ _ (E10_4 a) = E10_4 a
+  bimap _ _ (E10_5 a) = E10_5 a
+  bimap _ _ (E10_6 a) = E10_6 a
+  bimap _ _ (E10_7 a) = E10_7 a
+  bimap _ _ (E10_8 a) = E10_8 a
+  bimap f _ (E10_9 a) = E10_9 (f a)
+  bimap _ g (E10_10 a) = E10_10 (g a)
+
 instance Monad (Either3 a b) where
   E3_1 a >>= _ = E3_1 a
   E3_2 a >>= _ = E3_2 a
@@ -80,6 +195,56 @@
   E5_4 a >>= _ = E5_4 a
   E5_5 a >>= f = f a
 
+instance Monad (Either6 a b c d e) where
+  E6_1 a >>= _ = E6_1 a
+  E6_2 a >>= _ = E6_2 a
+  E6_3 a >>= _ = E6_3 a
+  E6_4 a >>= _ = E6_4 a
+  E6_5 a >>= _ = E6_5 a
+  E6_6 a >>= f = f a
+
+instance Monad (Either7 a b c d e f) where
+  E7_1 a >>= _ = E7_1 a
+  E7_2 a >>= _ = E7_2 a
+  E7_3 a >>= _ = E7_3 a
+  E7_4 a >>= _ = E7_4 a
+  E7_5 a >>= _ = E7_5 a
+  E7_6 a >>= _ = E7_6 a
+  E7_7 a >>= f = f a
+
+instance Monad (Either8 a b c d e f g) where
+  E8_1 a >>= _ = E8_1 a
+  E8_2 a >>= _ = E8_2 a
+  E8_3 a >>= _ = E8_3 a
+  E8_4 a >>= _ = E8_4 a
+  E8_5 a >>= _ = E8_5 a
+  E8_6 a >>= _ = E8_6 a
+  E8_7 a >>= _ = E8_7 a
+  E8_8 a >>= f = f a
+
+instance Monad (Either9 a b c d e f g h) where
+  E9_1 a >>= _ = E9_1 a
+  E9_2 a >>= _ = E9_2 a
+  E9_3 a >>= _ = E9_3 a
+  E9_4 a >>= _ = E9_4 a
+  E9_5 a >>= _ = E9_5 a
+  E9_6 a >>= _ = E9_6 a
+  E9_7 a >>= _ = E9_7 a
+  E9_8 a >>= _ = E9_8 a
+  E9_9 a >>= f = f a
+
+instance Monad (Either10 a b c d e f g h i) where
+  E10_1 a >>= _ = E10_1 a
+  E10_2 a >>= _ = E10_2 a
+  E10_3 a >>= _ = E10_3 a
+  E10_4 a >>= _ = E10_4 a
+  E10_5 a >>= _ = E10_5 a
+  E10_6 a >>= _ = E10_6 a
+  E10_7 a >>= _ = E10_7 a
+  E10_8 a >>= _ = E10_8 a
+  E10_9 a >>= _ = E10_9 a
+  E10_10 a >>= f = f a
+
 instance Bifoldable (Either3 a) where
   bifoldMap f _ (E3_2 a) = f a
   bifoldMap _ g (E3_3 a) = g a
@@ -95,6 +260,31 @@
   bifoldMap _ g (E5_5 a) = g a
   bifoldMap _ _ _        = mempty
 
+instance Bifoldable (Either6 a b c d) where
+  bifoldMap f _ (E6_5 a) = f a
+  bifoldMap _ g (E6_6 a) = g a
+  bifoldMap _ _ _        = mempty
+
+instance Bifoldable (Either7 a b c d e) where
+  bifoldMap f _ (E7_6 a) = f a
+  bifoldMap _ g (E7_7 a) = g a
+  bifoldMap _ _ _        = mempty
+
+instance Bifoldable (Either8 a b c d e f) where
+  bifoldMap f _ (E8_7 a) = f a
+  bifoldMap _ g (E8_8 a) = g a
+  bifoldMap _ _ _        = mempty
+
+instance Bifoldable (Either9 a b c d e f g) where
+  bifoldMap f _ (E9_8 a) = f a
+  bifoldMap _ g (E9_9 a) = g a
+  bifoldMap _ _ _        = mempty
+
+instance Bifoldable (Either10 a b c d e f g h) where
+  bifoldMap f _ (E10_9 a) = f a
+  bifoldMap _ g (E10_10 a) = g a
+  bifoldMap _ _ _        = mempty
+
 instance Bitraversable (Either3 a) where
   bitraverse _ _ (E3_1 a) = pure (E3_1 a)
   bitraverse f _ (E3_2 a) = E3_2 <$> f a
@@ -113,6 +303,56 @@
   bitraverse f _ (E5_4 a) = E5_4 <$> f a
   bitraverse _ g (E5_5 a) = E5_5 <$> g a
 
+instance Bitraversable (Either6 a b c d) where
+  bitraverse _ _ (E6_1 a) = pure (E6_1 a)
+  bitraverse _ _ (E6_2 a) = pure (E6_2 a)
+  bitraverse _ _ (E6_3 a) = pure (E6_3 a)
+  bitraverse _ _ (E6_4 a) = pure (E6_4 a)
+  bitraverse f _ (E6_5 a) = E6_5 <$> f a
+  bitraverse _ g (E6_6 a) = E6_6 <$> g a
+
+instance Bitraversable (Either7 a b c d e) where
+  bitraverse _ _ (E7_1 a) = pure (E7_1 a)
+  bitraverse _ _ (E7_2 a) = pure (E7_2 a)
+  bitraverse _ _ (E7_3 a) = pure (E7_3 a)
+  bitraverse _ _ (E7_4 a) = pure (E7_4 a)
+  bitraverse _ _ (E7_5 a) = pure (E7_5 a)
+  bitraverse f _ (E7_6 a) = E7_6 <$> (f a)
+  bitraverse _ g (E7_7 a) = E7_7 <$> (g a)
+
+instance Bitraversable (Either8 a b c d e f) where
+  bitraverse _ _ (E8_1 a) = pure (E8_1 a)
+  bitraverse _ _ (E8_2 a) = pure (E8_2 a)
+  bitraverse _ _ (E8_3 a) = pure (E8_3 a)
+  bitraverse _ _ (E8_4 a) = pure (E8_4 a)
+  bitraverse _ _ (E8_5 a) = pure (E8_5 a)
+  bitraverse _ _ (E8_6 a) = pure (E8_6 a)
+  bitraverse f _ (E8_7 a) = E8_7 <$> (f a)
+  bitraverse _ g (E8_8 a) = E8_8 <$> (g a)
+
+instance Bitraversable (Either9 a b c d e f g) where
+  bitraverse _ _ (E9_1 a) = pure (E9_1 a)
+  bitraverse _ _ (E9_2 a) = pure (E9_2 a)
+  bitraverse _ _ (E9_3 a) = pure (E9_3 a)
+  bitraverse _ _ (E9_4 a) = pure (E9_4 a)
+  bitraverse _ _ (E9_5 a) = pure (E9_5 a)
+  bitraverse _ _ (E9_6 a) = pure (E9_6 a)
+  bitraverse _ _ (E9_7 a) = pure (E9_7 a)
+  bitraverse f _ (E9_8 a) = E9_8 <$> (f a)
+  bitraverse _ g (E9_9 a) = E9_9 <$> (g a)
+
+instance Bitraversable (Either10 a b c d e f g h) where
+  bitraverse _ _ (E10_1 a) = pure (E10_1 a)
+  bitraverse _ _ (E10_2 a) = pure (E10_2 a)
+  bitraverse _ _ (E10_3 a) = pure (E10_3 a)
+  bitraverse _ _ (E10_4 a) = pure (E10_4 a)
+  bitraverse _ _ (E10_5 a) = pure (E10_5 a)
+  bitraverse _ _ (E10_6 a) = pure (E10_6 a)
+  bitraverse _ _ (E10_7 a) = pure (E10_7 a)
+  bitraverse _ _ (E10_8 a) = pure (E10_8 a)
+  bitraverse f _ (E10_9 a) = E10_9 <$> (f a)
+  bitraverse _ g (E10_10 a) = E10_10 <$> (g a)
+
 instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c) => HasAvroSchema (Either3 a b c) where
   schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
                              untag (schema :: Tagged b Schema),
@@ -134,6 +374,67 @@
                              untag (schema :: Tagged e Schema)
                             ])
 
+instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e, HasAvroSchema f)
+  => HasAvroSchema (Either6 a b c d e f) where
+    schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
+                               untag (schema :: Tagged b Schema),
+                               untag (schema :: Tagged c Schema),
+                               untag (schema :: Tagged d Schema),
+                               untag (schema :: Tagged e Schema),
+                               untag (schema :: Tagged f Schema)
+                              ])
+
+instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e, HasAvroSchema f, HasAvroSchema g)
+  => HasAvroSchema (Either7 a b c d e f g) where
+    schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
+                               untag (schema :: Tagged b Schema),
+                               untag (schema :: Tagged c Schema),
+                               untag (schema :: Tagged d Schema),
+                               untag (schema :: Tagged e Schema),
+                               untag (schema :: Tagged f Schema),
+                               untag (schema :: Tagged g Schema)
+                              ])
+
+instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e, HasAvroSchema f, HasAvroSchema g, HasAvroSchema h)
+  => HasAvroSchema (Either8 a b c d e f g h) where
+    schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
+                               untag (schema :: Tagged b Schema),
+                               untag (schema :: Tagged c Schema),
+                               untag (schema :: Tagged d Schema),
+                               untag (schema :: Tagged e Schema),
+                               untag (schema :: Tagged f Schema),
+                               untag (schema :: Tagged g Schema),
+                               untag (schema :: Tagged h Schema)
+                              ])
+
+instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e, HasAvroSchema f, HasAvroSchema g, HasAvroSchema h, HasAvroSchema i)
+  => HasAvroSchema (Either9 a b c d e f g h i) where
+    schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
+                               untag (schema :: Tagged b Schema),
+                               untag (schema :: Tagged c Schema),
+                               untag (schema :: Tagged d Schema),
+                               untag (schema :: Tagged e Schema),
+                               untag (schema :: Tagged f Schema),
+                               untag (schema :: Tagged g Schema),
+                               untag (schema :: Tagged h Schema),
+                               untag (schema :: Tagged i Schema)
+                              ])
+
+instance (HasAvroSchema a, HasAvroSchema b, HasAvroSchema c, HasAvroSchema d, HasAvroSchema e, HasAvroSchema f, HasAvroSchema g, HasAvroSchema h, HasAvroSchema i, HasAvroSchema j)
+  => HasAvroSchema (Either10 a b c d e f g h i j) where
+    schema = Tagged $ mkUnion (untag (schema :: Tagged a Schema) :| [
+                               untag (schema :: Tagged b Schema),
+                               untag (schema :: Tagged c Schema),
+                               untag (schema :: Tagged d Schema),
+                               untag (schema :: Tagged e Schema),
+                               untag (schema :: Tagged f Schema),
+                               untag (schema :: Tagged g Schema),
+                               untag (schema :: Tagged h Schema),
+                               untag (schema :: Tagged i Schema),
+                               untag (schema :: Tagged j Schema)
+                              ])
+
+
 instance (FromAvro a, FromAvro b, FromAvro c) => FromAvro (Either3 a b c) where
   fromAvro e@(T.Union _ branch x)
     | matches branch schemaA = E3_1 <$> fromAvro x
@@ -173,6 +474,111 @@
           Tagged schemaE = schema :: Tagged e Schema
   fromAvro x = badValue x "Either5"
 
+instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e, FromAvro f) => FromAvro (Either6 a b c d e f) where
+  fromAvro e@(T.Union _ branch x)
+    | matches branch schemaA = E6_1 <$> fromAvro x
+    | matches branch schemaB = E6_2 <$> fromAvro x
+    | matches branch schemaC = E6_3 <$> fromAvro x
+    | matches branch schemaD = E6_4 <$> fromAvro x
+    | matches branch schemaE = E6_5 <$> fromAvro x
+    | matches branch schemaF = E6_6 <$> fromAvro x
+    | otherwise              = badValue e "Either6"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+  fromAvro x = badValue x "Either6"
+
+instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e, FromAvro f, FromAvro g) => FromAvro (Either7 a b c d e f g) where
+  fromAvro e@(T.Union _ branch x)
+    | matches branch schemaA = E7_1 <$> fromAvro x
+    | matches branch schemaB = E7_2 <$> fromAvro x
+    | matches branch schemaC = E7_3 <$> fromAvro x
+    | matches branch schemaD = E7_4 <$> fromAvro x
+    | matches branch schemaE = E7_5 <$> fromAvro x
+    | matches branch schemaF = E7_6 <$> fromAvro x
+    | matches branch schemaG = E7_7 <$> fromAvro x
+      | otherwise              = badValue e "Either7"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+  fromAvro x = badValue x "Either7"
+
+instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e, FromAvro f, FromAvro g, FromAvro h) => FromAvro (Either8 a b c d e f g h) where
+  fromAvro e@(T.Union _ branch x)
+    | matches branch schemaA = E8_1 <$> fromAvro x
+    | matches branch schemaB = E8_2 <$> fromAvro x
+    | matches branch schemaC = E8_3 <$> fromAvro x
+    | matches branch schemaD = E8_4 <$> fromAvro x
+    | matches branch schemaE = E8_5 <$> fromAvro x
+    | matches branch schemaF = E8_6 <$> fromAvro x
+    | matches branch schemaG = E8_7 <$> fromAvro x
+    | matches branch schemaH = E8_8 <$> fromAvro x
+    | otherwise              = badValue e "Either8"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+  fromAvro x = badValue x "Either8"
+
+instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e, FromAvro f, FromAvro g, FromAvro h, FromAvro i) => FromAvro (Either9 a b c d e f g h i) where
+  fromAvro e@(T.Union _ branch x)
+    | matches branch schemaA = E9_1 <$> fromAvro x
+    | matches branch schemaB = E9_2 <$> fromAvro x
+    | matches branch schemaC = E9_3 <$> fromAvro x
+    | matches branch schemaD = E9_4 <$> fromAvro x
+    | matches branch schemaE = E9_5 <$> fromAvro x
+    | matches branch schemaF = E9_6 <$> fromAvro x
+    | matches branch schemaG = E9_7 <$> fromAvro x
+    | matches branch schemaH = E9_8 <$> fromAvro x
+    | matches branch schemaI = E9_9 <$> fromAvro x
+    | otherwise              = badValue e "Either9"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+          Tagged schemaI = schema :: Tagged i Schema
+  fromAvro x = badValue x "Either9"
+
+instance (FromAvro a, FromAvro b, FromAvro c, FromAvro d, FromAvro e, FromAvro f, FromAvro g, FromAvro h, FromAvro i, FromAvro j) => FromAvro (Either10 a b c d e f g h i j) where
+  fromAvro e@(T.Union _ branch x)
+    | matches branch schemaA = E10_1 <$> fromAvro x
+    | matches branch schemaB = E10_2 <$> fromAvro x
+    | matches branch schemaC = E10_3 <$> fromAvro x
+    | matches branch schemaD = E10_4 <$> fromAvro x
+    | matches branch schemaE = E10_5 <$> fromAvro x
+    | matches branch schemaF = E10_6 <$> fromAvro x
+    | matches branch schemaG = E10_7 <$> fromAvro x
+    | matches branch schemaH = E10_8 <$> fromAvro x
+    | matches branch schemaI = E10_9 <$> fromAvro x
+    | matches branch schemaJ = E10_10 <$> fromAvro x
+    | otherwise              = badValue e "Either10"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+          Tagged schemaI = schema :: Tagged i Schema
+          Tagged schemaJ = schema :: Tagged j Schema
+  fromAvro x = badValue x "Either10"
+
 instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c) => FromLazyAvro (Either3 a b c) where
   fromLazyAvro e@(AL.Union _ branch x)
     | matches branch schemaA = E3_1 <$> fromLazyAvro x
@@ -212,6 +618,111 @@
           Tagged schemaE = schema :: Tagged e Schema
   fromLazyAvro x = badValue x "Either5"
 
+instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c, FromLazyAvro d, FromLazyAvro e, FromLazyAvro f) => FromLazyAvro (Either6 a b c d e f) where
+  fromLazyAvro e@(AL.Union _ branch x)
+    | matches branch schemaA = E6_1 <$> fromLazyAvro x
+    | matches branch schemaB = E6_2 <$> fromLazyAvro x
+    | matches branch schemaC = E6_3 <$> fromLazyAvro x
+    | matches branch schemaD = E6_4 <$> fromLazyAvro x
+    | matches branch schemaE = E6_5 <$> fromLazyAvro x
+    | matches branch schemaF = E6_6 <$> fromLazyAvro x
+    | otherwise              = badValue e "Either6"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+  fromLazyAvro x = badValue x "Either6"
+
+instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c, FromLazyAvro d, FromLazyAvro e, FromLazyAvro f, FromLazyAvro g) => FromLazyAvro (Either7 a b c d e f g) where
+  fromLazyAvro e@(AL.Union _ branch x)
+    | matches branch schemaA = E7_1 <$> fromLazyAvro x
+    | matches branch schemaB = E7_2 <$> fromLazyAvro x
+    | matches branch schemaC = E7_3 <$> fromLazyAvro x
+    | matches branch schemaD = E7_4 <$> fromLazyAvro x
+    | matches branch schemaE = E7_5 <$> fromLazyAvro x
+    | matches branch schemaF = E7_6 <$> fromLazyAvro x
+    | matches branch schemaG = E7_7 <$> fromLazyAvro x
+      | otherwise              = badValue e "Either7"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+  fromLazyAvro x = badValue x "Either7"
+
+instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c, FromLazyAvro d, FromLazyAvro e, FromLazyAvro f, FromLazyAvro g, FromLazyAvro h) => FromLazyAvro (Either8 a b c d e f g h) where
+  fromLazyAvro e@(AL.Union _ branch x)
+    | matches branch schemaA = E8_1 <$> fromLazyAvro x
+    | matches branch schemaB = E8_2 <$> fromLazyAvro x
+    | matches branch schemaC = E8_3 <$> fromLazyAvro x
+    | matches branch schemaD = E8_4 <$> fromLazyAvro x
+    | matches branch schemaE = E8_5 <$> fromLazyAvro x
+    | matches branch schemaF = E8_6 <$> fromLazyAvro x
+    | matches branch schemaG = E8_7 <$> fromLazyAvro x
+    | matches branch schemaH = E8_8 <$> fromLazyAvro x
+    | otherwise              = badValue e "Either8"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+  fromLazyAvro x = badValue x "Either8"
+
+instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c, FromLazyAvro d, FromLazyAvro e, FromLazyAvro f, FromLazyAvro g, FromLazyAvro h, FromLazyAvro i) => FromLazyAvro (Either9 a b c d e f g h i) where
+  fromLazyAvro e@(AL.Union _ branch x)
+    | matches branch schemaA = E9_1 <$> fromLazyAvro x
+    | matches branch schemaB = E9_2 <$> fromLazyAvro x
+    | matches branch schemaC = E9_3 <$> fromLazyAvro x
+    | matches branch schemaD = E9_4 <$> fromLazyAvro x
+    | matches branch schemaE = E9_5 <$> fromLazyAvro x
+    | matches branch schemaF = E9_6 <$> fromLazyAvro x
+    | matches branch schemaG = E9_7 <$> fromLazyAvro x
+    | matches branch schemaH = E9_8 <$> fromLazyAvro x
+    | matches branch schemaI = E9_9 <$> fromLazyAvro x
+    | otherwise              = badValue e "Either9"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+          Tagged schemaI = schema :: Tagged i Schema
+  fromLazyAvro x = badValue x "Either9"
+
+instance (FromLazyAvro a, FromLazyAvro b, FromLazyAvro c, FromLazyAvro d, FromLazyAvro e, FromLazyAvro f, FromLazyAvro g, FromLazyAvro h, FromLazyAvro i, FromLazyAvro j) => FromLazyAvro (Either10 a b c d e f g h i j) where
+  fromLazyAvro e@(AL.Union _ branch x)
+    | matches branch schemaA = E10_1 <$> fromLazyAvro x
+    | matches branch schemaB = E10_2 <$> fromLazyAvro x
+    | matches branch schemaC = E10_3 <$> fromLazyAvro x
+    | matches branch schemaD = E10_4 <$> fromLazyAvro x
+    | matches branch schemaE = E10_5 <$> fromLazyAvro x
+    | matches branch schemaF = E10_6 <$> fromLazyAvro x
+    | matches branch schemaG = E10_7 <$> fromLazyAvro x
+    | matches branch schemaH = E10_8 <$> fromLazyAvro x
+    | matches branch schemaI = E10_9 <$> fromLazyAvro x
+    | matches branch schemaJ = E10_10 <$> fromLazyAvro x
+    | otherwise              = badValue e "Either10"
+    where Tagged schemaA = schema :: Tagged a Schema
+          Tagged schemaB = schema :: Tagged b Schema
+          Tagged schemaC = schema :: Tagged c Schema
+          Tagged schemaD = schema :: Tagged d Schema
+          Tagged schemaE = schema :: Tagged e Schema
+          Tagged schemaF = schema :: Tagged f Schema
+          Tagged schemaG = schema :: Tagged g Schema
+          Tagged schemaH = schema :: Tagged h Schema
+          Tagged schemaI = schema :: Tagged i Schema
+          Tagged schemaJ = schema :: Tagged j Schema
+  fromLazyAvro x = badValue x "Either10"
+
 instance (ToAvro a, ToAvro b, ToAvro c) => ToAvro (Either3 a b c) where
   toAvro e =
     let sch = options (schemaOf e)
@@ -238,3 +749,68 @@
       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)
+
+instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e, ToAvro f) => ToAvro (Either6 a b c d e f) where
+  toAvro e =
+    let sch = options (schemaOf e)
+    in case e of
+      E6_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E6_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E6_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E6_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E6_5 e -> T.Union sch (schemaOf e) (toAvro e)
+      E6_6 f -> T.Union sch (schemaOf f) (toAvro f)
+
+instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e, ToAvro f, ToAvro g) => ToAvro (Either7 a b c d e f g) where
+  toAvro e =
+    let sch = options (schemaOf e)
+    in case e of
+      E7_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E7_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E7_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E7_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E7_5 e -> T.Union sch (schemaOf e) (toAvro e)
+      E7_6 f -> T.Union sch (schemaOf f) (toAvro f)
+      E7_7 g -> T.Union sch (schemaOf g) (toAvro g)
+
+instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e, ToAvro f, ToAvro g, ToAvro h) => ToAvro (Either8 a b c d e f g h) where
+  toAvro e =
+    let sch = options (schemaOf e)
+    in case e of
+      E8_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E8_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E8_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E8_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E8_5 e -> T.Union sch (schemaOf e) (toAvro e)
+      E8_6 f -> T.Union sch (schemaOf f) (toAvro f)
+      E8_7 g -> T.Union sch (schemaOf g) (toAvro g)
+      E8_8 h -> T.Union sch (schemaOf h) (toAvro h)
+
+instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e, ToAvro f, ToAvro g, ToAvro h, ToAvro i) => ToAvro (Either9 a b c d e f g h i) where
+  toAvro e =
+    let sch = options (schemaOf e)
+    in case e of
+      E9_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E9_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E9_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E9_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E9_5 e -> T.Union sch (schemaOf e) (toAvro e)
+      E9_6 f -> T.Union sch (schemaOf f) (toAvro f)
+      E9_7 g -> T.Union sch (schemaOf g) (toAvro g)
+      E9_8 h -> T.Union sch (schemaOf h) (toAvro h)
+      E9_9 i -> T.Union sch (schemaOf i) (toAvro i)
+
+instance (ToAvro a, ToAvro b, ToAvro c, ToAvro d, ToAvro e, ToAvro f, ToAvro g, ToAvro h, ToAvro i, ToAvro j) => ToAvro (Either10 a b c d e f g h i j) where
+  toAvro e =
+    let sch = options (schemaOf e)
+    in case e of
+      E10_1 a -> T.Union sch (schemaOf a) (toAvro a)
+      E10_2 b -> T.Union sch (schemaOf b) (toAvro b)
+      E10_3 c -> T.Union sch (schemaOf c) (toAvro c)
+      E10_4 d -> T.Union sch (schemaOf d) (toAvro d)
+      E10_5 e -> T.Union sch (schemaOf e) (toAvro e)
+      E10_6 f -> T.Union sch (schemaOf f) (toAvro f)
+      E10_7 g -> T.Union sch (schemaOf g) (toAvro g)
+      E10_8 h -> T.Union sch (schemaOf h) (toAvro h)
+      E10_9 i -> T.Union sch (schemaOf i) (toAvro i)
+      E10_10 j -> T.Union sch (schemaOf j) (toAvro j)
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
@@ -3,7 +3,6 @@
 {-# LANGUAGE RecordWildCards      #-}
 {-# LANGUAGE ScopedTypeVariables  #-}
 {-# LANGUAGE TypeFamilies         #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 
 module Data.Avro.Encode
   ( -- * High level interface
@@ -40,7 +39,7 @@
 import           Data.List                  as DL
 import           Data.List.NonEmpty         (NonEmpty (..))
 import qualified Data.List.NonEmpty         as NE
-import           Data.Maybe                 (catMaybes, mapMaybe)
+import           Data.Maybe                 (catMaybes, mapMaybe, fromJust)
 import           Data.Monoid
 import           Data.Proxy
 import qualified Data.Set                   as S
@@ -49,9 +48,12 @@
 import qualified Data.Text.Encoding         as T
 import qualified Data.Text.Lazy             as TL
 import qualified Data.Text.Lazy.Encoding    as TL
+import qualified Data.Time                  as Time
+import qualified Data.UUID                  as UUID
 import qualified Data.Vector                as V
 import qualified Data.Vector.Unboxed        as U
 import           Data.Word
+import           GHC.TypeLits
 import           Prelude                    as P
 import           System.Random.TF.Init      (initTFGen)
 import           System.Random.TF.Instances (randoms)
@@ -61,6 +63,8 @@
 import Data.Avro.HasAvroSchema
 import Data.Avro.Schema        as S
 import Data.Avro.Types         as T
+import Data.Avro.Types.Decimal as D
+import Data.Avro.Types.Time
 import Data.Avro.Zag
 import Data.Avro.Zig
 
@@ -176,10 +180,10 @@
   avro :: a -> AvroM
 
 avroInt :: forall a. (FiniteBits a, Integral a, EncodeRaw a) => a -> AvroM
-avroInt n = AvroM (encodeRaw n, S.Int)
+avroInt n = AvroM (encodeRaw n, S.Int Nothing)
 
 avroLong :: forall a. (FiniteBits a, Integral a, EncodeRaw a) => a -> AvroM
-avroLong n = AvroM (encodeRaw n, S.Long)
+avroLong n = AvroM (encodeRaw n, S.Long Nothing)
 
 -- Put a Haskell Int.
 putI :: Int -> Builder
@@ -206,17 +210,17 @@
 instance EncodeAvro Text where
   avro t =
     let bs = T.encodeUtf8 t
-    in AvroM (encodeRaw (B.length bs) <> byteString bs, S.String)
+    in AvroM (encodeRaw (B.length bs) <> byteString bs, S.String')
 instance EncodeAvro TL.Text where
   avro t =
     let bs = TL.encodeUtf8 t
-    in AvroM (encodeRaw (BL.length bs) <> lazyByteString bs, S.String)
+    in AvroM (encodeRaw (BL.length bs) <> lazyByteString bs, S.String')
 
 instance EncodeAvro ByteString where
-  avro bs = AvroM (encodeRaw (BL.length bs) <> lazyByteString bs, S.Bytes)
+  avro bs = AvroM (encodeRaw (BL.length bs) <> lazyByteString bs, S.Bytes Nothing)
 
 instance EncodeAvro B.ByteString where
-  avro bs = AvroM (encodeRaw (B.length bs) <> byteString bs, S.Bytes)
+  avro bs = AvroM (encodeRaw (B.length bs) <> byteString bs, S.Bytes Nothing)
 
 instance EncodeAvro String where
   avro s = let t = T.pack s in avro t
@@ -227,6 +231,25 @@
 instance EncodeAvro Float where
   avro d = AvroM (word32LE (IEEE.floatToWord d), S.Float)
 
+instance (KnownNat p, KnownNat s) => EncodeAvro (D.Decimal p s) where
+  avro d = AvroM (encodeRaw val, S.Long (Just (DecimalL (S.Decimal pp ss))))
+    where ss = natVal (Proxy :: Proxy s)
+          pp = natVal (Proxy :: Proxy p)
+          val :: Int = fromJust $ D.underlyingValue d
+
+instance EncodeAvro UUID.UUID where
+  avro d =
+    let bs = T.encodeUtf8 (UUID.toText d)
+    in AvroM (encodeRaw (B.length bs) <> byteString bs, S.String (Just UUID))
+
+instance EncodeAvro Time.Day where
+  avro d = AvroM ( encodeRaw (fromIntegral $ daysSinceEpoch d :: Int)
+                 , S.Int (Just Date) )
+
+instance EncodeAvro Time.DiffTime where
+  avro d = AvroM ( encodeRaw (fromIntegral $ diffTimeToMicros d :: Int)
+                 , S.Long (Just TimeMicros) )
+
 -- Terminating word for array and map types.
 long0 :: Builder
 long0 = encodeRaw (0 :: Word64)
@@ -265,8 +288,8 @@
 
 -- | Maybe is modeled as a sum type `{null, a}`.
 instance EncodeAvro a => EncodeAvro (Maybe a) where
-  avro Nothing  = AvroM (putI 0             , S.mkUnion (S.Null:|[S.Int]))
-  avro (Just x) = AvroM (putI 1 <> putAvro x, S.mkUnion (S.Null:|[S.Int]))
+  avro Nothing  = AvroM (putI 0             , S.mkUnion (S.Null:|[S.Int']))
+  avro (Just x) = AvroM (putI 1 <> putAvro x, S.mkUnion (S.Null:|[S.Int']))
 
 instance EncodeAvro () where
   avro () = AvroM (mempty, S.Null)
@@ -301,7 +324,7 @@
       T.Enum sch@S.Enum{..} ix t -> AvroM (putI ix, sch)
       T.Fixed ty bs  ->
         if (B.length bs == size ty)
-          then AvroM (byteString bs, S.Bytes)
+          then AvroM (byteString bs, S.Bytes Nothing)
           else error $ "Fixed type "  <> show (name ty)
                       <> " has size " <> show (size ty)
                       <> " but the value has length " <> show (B.length 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
@@ -8,10 +8,13 @@
 where
 
 import           Control.Arrow           (first)
+import           Control.Monad.Identity  (Identity(..))
 import qualified Data.Avro.Encode        as E
 import           Data.Avro.HasAvroSchema
 import           Data.Avro.Schema        as S
 import           Data.Avro.Types         as T
+import           Data.Avro.Types.Decimal as D
+import           Data.Avro.Types.Time
 import qualified Data.ByteString         as B
 import           Data.ByteString.Lazy    (ByteString)
 import qualified Data.ByteString.Lazy    as BL
@@ -25,9 +28,12 @@
 import           Data.Text               (Text)
 import qualified Data.Text               as Text
 import qualified Data.Text.Lazy          as TL
+import qualified Data.Time               as Time
+import qualified Data.UUID               as UUID
 import qualified Data.Vector             as V
 import qualified Data.Vector.Unboxed     as U
 import           Data.Word
+import           GHC.TypeLits
 
 class HasAvroSchema a => FromAvro a where
   fromAvro :: Value Schema -> Result a
@@ -38,6 +44,13 @@
     Nothing -> fail $ "Requested field not available: " <> show key
     Just v  -> fromAvro v
 
+instance (FromAvro a) => FromAvro (Identity a) where
+  fromAvro e@(T.Union _ branch x)
+    | S.matches branch sch = Identity <$> fromAvro x
+    | otherwise            = badValue e "Identity"
+    where Tagged sch = schema :: Tagged a Schema
+  fromAvro x = badValue x "Identity"
+
 instance (FromAvro a, FromAvro b) => FromAvro (Either a b) where
   fromAvro e@(T.Union _ branch x)
     | S.matches branch schemaA = Left  <$> fromAvro x
@@ -83,6 +96,28 @@
   fromAvro (T.Float f) = pure f
   fromAvro v           = badValue v "Float"
 
+instance (KnownNat p, KnownNat s) => FromAvro (D.Decimal p s) where
+  fromAvro (T.Long n) = pure $ D.fromUnderlyingValue $ fromIntegral n
+  fromAvro (T.Int  n) = pure $ D.fromUnderlyingValue $ fromIntegral n
+  fromAvro v          = badValue v "Decimal"
+
+instance FromAvro UUID.UUID where
+  fromAvro v@(T.String s)
+    = case UUID.fromText s of
+        Nothing -> badValue v "UUID"
+        Just u  -> pure u
+  fromAvro v = badValue v "UUID"
+
+instance FromAvro Time.Day where
+  fromAvro (T.Int  v) = pure $ fromDaysSinceEpoch (toInteger v)
+  fromAvro (T.Long v) = pure $ fromDaysSinceEpoch (toInteger v)
+  fromAvro v = badValue v "Date"
+
+instance FromAvro Time.DiffTime where
+  fromAvro (T.Int  v) = pure $ microsToDiffTime (toInteger v)
+  fromAvro (T.Long v) = pure $ microsToDiffTime (toInteger v)
+  fromAvro v = badValue v "TimeMicros"
+
 instance FromAvro a => FromAvro (Maybe a) where
   fromAvro (T.Union ts _ v) = case (V.toList ts, v) of
     ([S.Null, _], T.Null) -> pure Nothing
@@ -119,4 +154,3 @@
   fromAvro (T.Record _ mp) = mapM fromAvro mp
   fromAvro (T.Map mp)      = mapM fromAvro mp
   fromAvro v               = badValue v "HashMap Text a"
-
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
@@ -1,30 +1,34 @@
 {-# LANGUAGE ConstraintKinds      #-}
 {-# LANGUAGE FlexibleInstances    #-}
 {-# LANGUAGE ScopedTypeVariables  #-}
-{-# LANGUAGE TypeSynonymInstances #-}
 module Data.Avro.HasAvroSchema where
 
-import qualified Data.Array           as Ar
-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           Control.Monad.Identity  (Identity)
+import qualified Data.Array              as Ar
+import           Data.Avro.Schema        as S
+import           Data.Avro.Types         as T
+import           Data.Avro.Types.Decimal as D
+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.Ix              (Ix)
-import           Data.List.NonEmpty   (NonEmpty (..))
-import qualified Data.Map             as Map
-import           Data.Monoid          ((<>))
+import           Data.Ix                (Ix)
+import           Data.List.NonEmpty     (NonEmpty (..))
+import qualified Data.Map               as Map
+import           Data.Monoid            ((<>))
 import           Data.Proxy
-import qualified Data.Set             as S
+import qualified Data.Set               as S
 import           Data.Tagged
 import           Data.Text            (Text)
 import qualified Data.Text            as Text
 import qualified Data.Text.Lazy       as TL
+import qualified Data.Time            as Time
+import qualified Data.UUID            as UUID
 import qualified Data.Vector          as V
 import qualified Data.Vector.Unboxed  as U
 import           Data.Word
+import           GHC.TypeLits
 
 class HasAvroSchema a where
   schema :: Tagged a Schema
@@ -33,16 +37,16 @@
 schemaOf = witness schema
 
 instance HasAvroSchema Word8 where
-  schema = Tagged S.Int
+  schema = Tagged S.Int'
 
 instance HasAvroSchema Word16 where
-  schema = Tagged S.Int
+  schema = Tagged S.Int'
 
 instance HasAvroSchema Word32 where
-  schema = Tagged S.Long
+  schema = Tagged S.Long'
 
 instance HasAvroSchema Word64 where
-  schema = Tagged S.Long
+  schema = Tagged S.Long'
 
 instance HasAvroSchema Bool where
   schema = Tagged S.Boolean
@@ -51,19 +55,19 @@
   schema = Tagged S.Null
 
 instance HasAvroSchema Int where
-  schema = Tagged S.Long
+  schema = Tagged S.Long'
 
 instance HasAvroSchema Int8 where
-  schema = Tagged S.Int
+  schema = Tagged S.Int'
 
 instance HasAvroSchema Int16 where
-  schema = Tagged S.Int
+  schema = Tagged S.Int'
 
 instance HasAvroSchema Int32 where
-  schema = Tagged S.Int
+  schema = Tagged S.Int'
 
 instance HasAvroSchema Int64 where
-  schema = Tagged S.Long
+  schema = Tagged S.Long'
 
 instance HasAvroSchema Double where
   schema = Tagged S.Double
@@ -72,16 +76,36 @@
   schema = Tagged S.Float
 
 instance HasAvroSchema Text.Text where
-  schema = Tagged S.String
+  schema = Tagged S.String'
 
 instance HasAvroSchema TL.Text where
-  schema = Tagged S.String
+  schema = Tagged S.String'
 
 instance HasAvroSchema B.ByteString where
-  schema = Tagged S.Bytes
+  schema = Tagged S.Bytes'
 
 instance HasAvroSchema BL.ByteString where
-  schema = Tagged S.Bytes
+  schema = Tagged S.Bytes'
+
+instance (KnownNat p, KnownNat s) => HasAvroSchema (D.Decimal p s) where
+  schema = Tagged $ S.Long (Just (DecimalL (S.Decimal pp ss)))
+    where ss = natVal (Proxy :: Proxy s)
+          pp = natVal (Proxy :: Proxy p)
+
+instance HasAvroSchema UUID.UUID where
+  schema = Tagged $ S.String (Just UUID)
+
+instance HasAvroSchema Time.Day where
+  schema = Tagged $ S.Int (Just Date)
+
+instance HasAvroSchema Time.DiffTime where
+  schema = Tagged $ S.Long (Just TimeMicros)
+
+instance HasAvroSchema Time.UTCTime where
+  schema = Tagged $ S.Long (Just TimestampMicros)
+
+instance (HasAvroSchema a) => HasAvroSchema (Identity a) where
+  schema = Tagged $ S.Union $ V.fromListN 1 [untag (schema :: Tagged a Schema)]
 
 instance (HasAvroSchema a, HasAvroSchema b) => HasAvroSchema (Either a b) where
   schema = Tagged $ S.Union $ V.fromListN 2 [untag (schema :: Tagged a Schema), untag (schema :: Tagged b Schema)]
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
@@ -6,6 +6,7 @@
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE NamedFieldPuns        #-}
 {-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE PatternSynonyms       #-}
 {-# LANGUAGE RecordWildCards       #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
 {-# LANGUAGE TupleSections         #-}
@@ -20,9 +21,13 @@
 module Data.Avro.Schema
   (
    -- * Schema description types
-    Schema(..), Type
+    Schema(.., Int', Long', Bytes', String'), Type
   , Field(..), Order(..)
   , TypeName(..)
+  , Decimal(..)
+  , LogicalTypeBytes(..), LogicalTypeFixed(..)
+  , LogicalTypeInt(..), LogicalTypeLong(..)
+  , LogicalTypeString(..)
   , renderFullname
   , parseFullname
   , mkEnum, mkUnion
@@ -94,11 +99,13 @@
       -- Basic types
         Null
       | Boolean
-      | Int   | Long
+      | Int    { logicalTypeI :: Maybe LogicalTypeInt }
+      | Long   { logicalTypeL :: Maybe LogicalTypeLong }
       | Float | Double
-      | Bytes | String
-      | Array { item :: Schema }
-      | Map   { values :: Schema }
+      | Bytes  { logicalTypeB :: Maybe LogicalTypeBytes }
+      | String { logicalTypeS :: Maybe LogicalTypeString }
+      | Array  { item :: Schema }
+      | Map    { values :: Schema }
       | NamedType TypeName
       -- Declared types
       | Record { name    :: TypeName
@@ -114,33 +121,63 @@
              }
       | Union { options     :: V.Vector Schema
               }
-      | Fixed { name    :: TypeName
-              , aliases :: [TypeName]
-              , size    :: Int
+      | Fixed { name         :: TypeName
+              , aliases      :: [TypeName]
+              , size         :: Int
+              , logicalTypeF :: Maybe LogicalTypeFixed
               }
-    deriving (Show, Generic, NFData)
+    deriving (Ord, Show, Generic, NFData)
 
+pattern Int'    = Int    Nothing
+pattern Long'   = Long   Nothing
+pattern Bytes'  = Bytes  Nothing
+pattern String' = String Nothing
+
+data Decimal
+  = Decimal { precision :: Integer, scale :: Integer }
+  deriving (Eq, Show, Ord, Generic, NFData)
+
+newtype LogicalTypeBytes
+  = DecimalB Decimal
+  deriving (Eq, Show, Ord, Generic, NFData)
+
+data LogicalTypeFixed
+  = DecimalF Decimal | Duration
+  deriving (Eq, Show, Ord, Generic, NFData)
+
+data LogicalTypeInt
+  = DecimalI Decimal | Date | TimeMillis
+  deriving (Eq, Show, Ord, Generic, NFData)
+
+data LogicalTypeLong
+  = DecimalL Decimal | TimeMicros | TimestampMillis | TimestampMicros
+  deriving (Eq, Show, Ord, Generic, NFData)
+
+data LogicalTypeString
+  = UUID
+  deriving (Eq, Show, Ord, Generic, NFData)
+
 instance Eq Schema where
   Null == Null = True
   Boolean == Boolean = True
-  Int == Int = True
-  Long == Long = True
+  Int lt1 == Int lt2 = lt1 == lt2
+  Long lt1 == Long lt2 = lt1 == lt2
   Float == Float = True
   Double == Double = True
-  Bytes == Bytes = True
-  String == String = True
+  Bytes lt1 == Bytes lt2 = lt1 == lt2
+  String lt1 == String lt2 = lt1 == lt2
 
   Array ty == Array ty2 = ty == ty2
   Map ty == Map ty2 = ty == ty2
   NamedType t == NamedType t2 = t == t2
 
   Record name1 _ _ _ fs1 == Record name2 _ _ _ fs2 =
-    and [name1 == name2, fs1 == fs2]
+    (name1 == name2) && (fs1 == fs2)
   Enum name1 _ _ s == Enum name2 _ _ s2 =
-    and [name1 == name2, s == s2]
+    (name1 == name2) && (s == s2)
   Union a == Union b = a == b
-  Fixed name1 _ s == Fixed name2 _ s2 =
-    and [name1 == name2, s == s2]
+  Fixed name1 _ s lt1 == Fixed name2 _ s2 lt2 =
+    (name1 == name2) && (s == s2) && (lt1 == lt2)
 
   _ == _ = False
 
@@ -256,7 +293,7 @@
   | isFullName name = parseFullname name
   | otherwise       = case ns of
       Just ns -> TN name $ filter (/= "") (T.splitOn "." ns)
-      Nothing -> TN name $ fromMaybe [] $ namespace <$> context
+      Nothing -> TN name $ maybe [] namespace context
   where isFullName = isJust . T.find (== '.')
 
 -- | This lets us write 'TypeName's as string literals in a fully
@@ -275,19 +312,42 @@
 typeName :: Schema -> Text
 typeName bt =
   case bt of
-    Null           -> "null"
-    Boolean        -> "boolean"
-    Int            -> "int"
-    Long           -> "long"
-    Float          -> "float"
-    Double         -> "double"
-    Bytes          -> "bytes"
-    String         -> "string"
-    Array _        -> "array"
-    Map   _        -> "map"
-    NamedType name -> renderFullname name
-    Union ts       -> typeName (V.head ts)
-    _              -> renderFullname $ name bt
+    Null            -> "null"
+    Boolean         -> "boolean"
+    Int Nothing     -> "int"
+    Int (Just (DecimalI d))
+                    -> decimalName d
+    Int (Just Date) -> "date"
+    Int (Just TimeMillis)
+                    -> "time-millis"
+    Long Nothing    -> "long"
+    Long (Just (DecimalL d))
+                    -> decimalName d
+    Long (Just TimeMicros)
+                    -> "time-micros"
+    Long (Just TimestampMillis)
+                    -> "timestamp-millis"
+    Long (Just TimestampMicros)
+                    -> "timestamp-micros"
+    Float           -> "float"
+    Double          -> "double"
+    Bytes Nothing   -> "bytes"
+    Bytes (Just (DecimalB d))
+                    -> decimalName d
+    String Nothing  -> "string"
+    String (Just UUID)
+                    -> "uuid"
+    Array _         -> "array"
+    Map   _         -> "map"
+    NamedType name  -> renderFullname name
+    Union ts        -> typeName (V.head ts)
+    Fixed _ _ _ (Just (DecimalF d))
+                    -> decimalName d
+    Fixed _ _ _ (Just Duration)
+                    -> "duration"
+    _               -> renderFullname $ name bt
+  where
+    decimalName (Decimal prec sc) = "decimal(" <> T.pack (show prec) <> "," <> T.pack (show sc) <> ")"
 
 data Field = Field { fldName    :: Text
                    , fldAliases :: [Text]
@@ -296,7 +356,7 @@
                    , fldType    :: Schema
                    , fldDefault :: Maybe (Ty.Value Schema)
                    }
-  deriving (Eq, Show, Generic, NFData)
+  deriving (Eq, Ord, Show, Generic, NFData)
 
 data Order = Ascending | Descending | Ignore
   deriving (Eq, Ord, Show, Generic, NFData)
@@ -318,12 +378,18 @@
   A.String s -> case s of
     "null"    -> return Null
     "boolean" -> return Boolean
-    "int"     -> return Int
-    "long"    -> return Long
+    "int"     -> return $ Int Nothing
+    "long"    -> return $ Long Nothing
     "float"   -> return Float
     "double"  -> return Double
-    "bytes"   -> return Bytes
-    "string"  -> return String
+    "bytes"   -> return $ Bytes Nothing
+    "string"  -> return $ String Nothing
+    "uuid"    -> return $ String (Just UUID)
+    "date"    -> return $ Int (Just Date)
+    "time-millis" -> return $ Int (Just TimeMillis)
+    "time-micros" -> return $ Long (Just TimeMicros)
+    "timestamp-millis" -> return $ Long (Just TimestampMillis)
+    "timestamp-micros" -> return $ Long (Just TimestampMicros)
     somename  -> return $ NamedType $ mkTypeName context somename Nothing
   A.Array arr
     | V.length arr > 0 ->
@@ -334,6 +400,37 @@
     ty                        <- o .: "type"
 
     case logicalType of
+      Just "decimal" -> do
+        prec <- o .: "precision"
+        sc   <- fromMaybe 0 <$> o .:? "scale"
+        let dec = Decimal prec sc
+        case ty of
+          "bytes" -> pure $ Bytes (Just (DecimalB dec))
+          "fixed" -> (\fx -> fx { logicalTypeF = Just (DecimalF dec) }) <$> parseFixed o
+          "int"   -> pure $ Int (Just (DecimalI dec))
+          "long"  -> pure $ Long (Just (DecimalL dec))
+          s       -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "uuid" -> case ty of
+          "string" -> pure $ String (Just UUID)
+          s        -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "date" -> case ty of
+          "int" -> pure $ Int (Just Date)
+          s     -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "time-millis" -> case ty of
+          "int" -> pure $ Int (Just TimeMillis)
+          s     -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "time-micros" -> case ty of
+          "long" -> pure $ Long (Just TimeMicros)
+          s      -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "timestamp-millis" -> case ty of
+          "long" -> pure $ Long (Just TimestampMillis)
+          s      -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "timestamp-micros" -> case ty of
+          "long" -> pure $ Long (Just TimestampMicros)
+          s      -> fail $ "Unsupported underlying type: " <> T.unpack s
+      Just "duration" -> case ty of
+          "fixed" -> (\fx -> fx { logicalTypeF = Just Duration }) <$> parseFixed o
+          s      -> fail $ "Unsupported underlying type: " <> T.unpack s
       Just _  -> parseJSON (A.String ty)
       Nothing -> case ty of
         "map"    -> Map <$> (parseSchemaJSON context =<< o .: "values")
@@ -357,26 +454,29 @@
           doc     <- o .:? "doc"
           symbols <- o .: "symbols"
           pure $ mkEnum typeName aliases doc symbols
-        "fixed"  -> do
-          name      <- o .: "name"
-          namespace <- o .:? "namespace"
-          let typeName = mkTypeName context name namespace
-              mkAlias name = mkTypeName (Just typeName) name Nothing
-          aliases <- mkAliases typeName <$> (o .:? "aliases" .!= [])
-          size    <- o .: "size"
-          pure $ Fixed typeName aliases size
+        "fixed"   -> parseFixed o
         "null"    -> pure Null
         "boolean" -> pure Boolean
-        "int"     -> pure Int
-        "long"    -> pure Long
+        "int"     -> pure $ Int Nothing
+        "long"    -> pure $ Long Nothing
         "float"   -> pure Float
         "double"  -> pure Double
-        "bytes"   -> pure Bytes
-        "string"  -> pure String
+        "bytes"   -> pure $ Bytes Nothing
+        "string"  -> pure $ String Nothing
         s        -> fail $ "Unrecognized object type: " <> T.unpack s
 
   invalid    -> typeMismatch "Invalid JSON for Avro Schema" invalid
 
+  where
+    parseFixed o = do
+      name      <- o .: "name"
+      namespace <- o .:? "namespace"
+      let typeName = mkTypeName context name namespace
+          mkAlias name = mkTypeName (Just typeName) name Nothing
+      aliases <- mkAliases typeName <$> (o .:? "aliases" .!= [])
+      size    <- o .: "size"
+      pure $ Fixed typeName aliases size Nothing
+
 -- | Parse aliases, inferring the namespace based on the type being aliases.
 mkAliases :: TypeName
              -- ^ The name of the type being aliased.
@@ -428,20 +528,41 @@
                 -- ^ The schema to serialize to JSON.
              -> A.Value
 schemaToJSON context = \case
-  Null           -> A.String "null"
-  Boolean        -> A.String "boolean"
-  Int            -> A.String "int"
-  Long           -> A.String "long"
-  Float          -> A.String "float"
-  Double         -> A.String "double"
-  Bytes          -> A.String "bytes"
-  String         -> A.String "string"
-  Array tn       ->
+  Null            -> A.String "null"
+  Boolean         -> A.String "boolean"
+  Int Nothing     -> A.String "int"
+  Int (Just (DecimalI (Decimal prec sc))) ->
+    object [ "type" .= ("int" :: Text), "logicalType" .= ("decimal" :: Text)
+           , "precision" .= prec, "scale" .= sc ]
+  Int (Just Date) ->
+    object [ "type" .= ("int" :: Text), "logicalType" .= ("date" :: Text) ]
+  Int (Just TimeMillis) ->
+    object [ "type" .= ("int" :: Text), "logicalType" .= ("time-millis" :: Text) ]
+  Long Nothing    -> A.String "long"
+  Long (Just (DecimalL (Decimal prec sc))) ->
+    object [ "type" .= ("long" :: Text), "logicalType" .= ("decimal" :: Text)
+           , "precision" .= prec, "scale" .= sc ]
+  Long (Just TimeMicros) ->
+    object [ "type" .= ("long" :: Text), "logicalType" .= ("time-micros" :: Text) ]
+  Long (Just TimestampMillis) ->
+    object [ "type" .= ("long" :: Text), "logicalType" .= ("timestamp-millis" :: Text) ]
+  Long (Just TimestampMicros) ->
+    object [ "type" .= ("long" :: Text), "logicalType" .= ("timestamp-micros" :: Text) ]
+  Float           -> A.String "float"
+  Double          -> A.String "double"
+  Bytes Nothing   -> A.String "bytes"
+  Bytes (Just (DecimalB (Decimal prec sc))) ->
+    object [ "type" .= ("bytes" :: Text), "logicalType" .= ("decimal" :: Text)
+           , "precision" .= prec, "scale" .= sc ]
+  String Nothing  -> A.String "string"
+  String (Just UUID) -> 
+    object [ "type" .= ("string" :: Text), "logicalType" .= ("uuid" :: Text) ]
+  Array tn        ->
     object [ "type" .= ("array" :: Text), "items" .= schemaToJSON context tn ]
-  Map tn         ->
+  Map tn          ->
     object [ "type" .= ("map" :: Text), "values" .= schemaToJSON context tn ]
-  NamedType name -> toJSON $ render context name
-  Record {..}    ->
+  NamedType name  -> toJSON $ render context name
+  Record {..}     ->
     let opts = catMaybes
           [ ("order" .=) <$> order
           , ("doc" .=)   <$> doc
@@ -462,11 +583,19 @@
        ]
   Union  {..} -> toJSON $ schemaToJSON context <$> options
   Fixed  {..} ->
-    object [ "type"    .= ("fixed" :: Text)
+    let basic = 
+           [ "type"    .= ("fixed" :: Text)
            , "name"    .= render context name
            , "aliases" .= (render (Just name) <$> aliases)
            , "size"    .= size
            ]
+        extended = case logicalTypeF of
+          Nothing       -> []
+          Just Duration -> [ "logicalType" .= ("duration" :: Text) ]
+          Just (DecimalF (Decimal prec sc))
+                   -> [ "logicalType" .= ("decimal" :: Text)
+                      , "precision" .= prec, "scale" .= sc ]
+    in object (basic ++ extended)
   where render context typeName
           | Just ctx <- context
           , namespace ctx == namespace typeName = baseName typeName
@@ -588,17 +717,17 @@
   case env name of
     Nothing -> fail $ "Could not resolve type name for " <> T.unpack (renderFullname name)
     Just t  -> parseAvroJSON union env t av
-parseAvroJSON union _ u@Union{} av             = union u av
+parseAvroJSON union _ u@Union{} av             = u `union` av
 parseAvroJSON union env ty av                  =
     case av of
       A.String s      ->
         case ty of
-          String      -> return $ Ty.String s
+          String _    -> return $ Ty.String s
           Enum {..}   ->
               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
+          Bytes _     -> Ty.Bytes <$> parseBytes s
           Fixed {..}  -> do
             bytes <- parseBytes s
             let len = B.length bytes
@@ -610,8 +739,8 @@
                           _       -> avroTypeMismatch ty "boolean"
       A.Number i     ->
         case ty of
-          Int    -> return $ Ty.Int    (floor i)
-          Long   -> return $ Ty.Long   (floor i)
+          Int _  -> return $ Ty.Int    (floor i)
+          Long _ -> return $ Ty.Long   (floor i)
           Float  -> return $ Ty.Float  (realToFrac i)
           Double -> return $ Ty.Double (realToFrac i)
           _      -> avroTypeMismatch ty "number"
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
@@ -5,10 +5,13 @@
 
 where
 
+import           Control.Monad.Identity  (Identity(..))
 import           Control.Arrow           (first)
 import           Data.Avro.HasAvroSchema
 import           Data.Avro.Schema        as S
 import           Data.Avro.Types         as T
+import           Data.Avro.Types.Decimal as D
+import           Data.Avro.Types.Time
 import qualified Data.ByteString         as B
 import           Data.ByteString.Lazy    (ByteString)
 import qualified Data.ByteString.Lazy    as BL
@@ -16,13 +19,17 @@
 import           Data.Int
 import           Data.List.NonEmpty      (NonEmpty (..))
 import qualified Data.Map                as Map
+import           Data.Maybe              (fromJust)
 import           Data.Tagged
 import           Data.Text               (Text)
 import qualified Data.Text               as Text
 import qualified Data.Text.Lazy          as TL
+import qualified Data.Time               as Time
+import qualified Data.UUID               as UUID
 import qualified Data.Vector             as V
 import qualified Data.Vector.Unboxed     as U
 import           Data.Word
+import           GHC.TypeLits
 
 class HasAvroSchema a => ToAvro a where
   toAvro :: a -> T.Value Schema
@@ -62,6 +69,24 @@
 
 instance ToAvro BL.ByteString where
   toAvro = T.Bytes . BL.toStrict
+
+instance (KnownNat p, KnownNat s) => ToAvro (D.Decimal p s) where
+  toAvro = T.Long . fromIntegral . fromJust . D.underlyingValue
+
+instance ToAvro UUID.UUID where
+  toAvro = T.String . UUID.toText
+
+instance ToAvro Time.Day where
+  toAvro = T.Long . fromIntegral . daysSinceEpoch
+
+instance ToAvro Time.DiffTime where
+  toAvro = T.Long . fromIntegral . diffTimeToMicros
+
+instance (ToAvro a) => ToAvro (Identity a) where
+  toAvro e@(Identity a) =
+    let sch = options (schemaOf e)
+    in
+      T.Union sch (schemaOf a) (toAvro a)
 
 instance (ToAvro a, ToAvro b) => ToAvro (Either a b) where
   toAvro e =
diff --git a/src/Data/Avro/Types/Decimal.hs b/src/Data/Avro/Types/Decimal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Avro/Types/Decimal.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE PolyKinds                  #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+module Data.Avro.Types.Decimal where
+
+import qualified Data.BigDecimal as D
+import           Data.Proxy
+import           GHC.TypeLits
+
+newtype Decimal (p :: Nat) (s :: Nat)
+  = Decimal { unDecimal :: D.BigDecimal }
+  deriving (Eq, Ord, Show, Read, Num, Fractional, Real)
+
+fromUnderlyingValue
+  :: forall p s. KnownNat s
+  => Integer -> Decimal p s
+fromUnderlyingValue n
+  = Decimal $ D.BigDecimal n (natVal (Proxy :: Proxy s))
+
+underlyingValue
+  :: forall s p. (KnownNat p, KnownNat s)
+  => Decimal p s -> Maybe Int
+underlyingValue (Decimal d)
+  = let ss = natVal (Proxy :: Proxy s)
+        pp = natVal (Proxy :: Proxy p)
+        new = if ss > D.getScale d
+                 then D.BigDecimal (D.getValue d * 10 ^ (ss - D.getScale d)) ss
+                 else D.roundBD d (D.halfUp ss)
+    in if D.precision new > pp
+          then Nothing
+          else Just $ fromInteger $ D.getValue new
diff --git a/src/Data/Avro/Types/Time.hs b/src/Data/Avro/Types/Time.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Avro/Types/Time.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE CPP #-}
+module Data.Avro.Types.Time where
+
+-- Utility functions to work with times
+
+import Data.Maybe (fromJust)
+import Data.Time
+import Data.Time.Clock
+#if MIN_VERSION_time(1,9,0)
+import Data.Time.Format.Internal
+#else
+import Data.Time.Format
+#endif
+
+epochDate :: Day
+epochDate = fromJust $ buildTime defaultTimeLocale []
+
+daysSinceEpoch :: Day -> Integer
+daysSinceEpoch d = diffDays d epochDate
+
+fromDaysSinceEpoch :: Integer -> Day
+fromDaysSinceEpoch n = addDays n epochDate
+
+diffTimeToMicros :: DiffTime -> Integer
+diffTimeToMicros = (`div` 1000000) . diffTimeToPicoseconds
+
+microsToDiffTime :: Integer -> DiffTime
+microsToDiffTime = picosecondsToDiffTime . (* 1000000)
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
@@ -28,4 +28,4 @@
       | 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)
+  deriving (Eq, Ord, Show, Generic, NFData)
diff --git a/test/Avro/Codec/Int64Spec.hs b/test/Avro/Codec/Int64Spec.hs
--- a/test/Avro/Codec/Int64Spec.hs
+++ b/test/Avro/Codec/Int64Spec.hs
@@ -34,7 +34,7 @@
 onlyInt64Schema =
   let fld nm = Field nm [] Nothing Nothing
    in Record "test.contract.OnlyInt64" [] Nothing Nothing
-        [ fld "onlyInt64Value"    Long Nothing
+        [ fld "onlyInt64Value"    Long' Nothing
         ]
 
 instance HasAvroSchema OnlyInt64 where
diff --git a/test/Avro/Codec/NestedSpec.hs b/test/Avro/Codec/NestedSpec.hs
--- a/test/Avro/Codec/NestedSpec.hs
+++ b/test/Avro/Codec/NestedSpec.hs
@@ -25,15 +25,15 @@
 childTypeSchema =
   let fld nm = Field nm [] Nothing Nothing
   in Record "test.contract.ChildType" [] Nothing Nothing
-        [ fld "childValue1" Long Nothing
-        , fld "childValue2" Long Nothing
+        [ fld "childValue1" Long' Nothing
+        , fld "childValue2" Long' Nothing
         ]
 
 parentTypeSchema :: Schema
 parentTypeSchema =
   let fld nm = Field nm [] Nothing Nothing
   in Record "test.contract.ParentType" [] Nothing Nothing
-        [ fld "parentValue1" Long             Nothing
+        [ fld "parentValue1" Long'             Nothing
         , fld "parentValue2" (Array childTypeSchema)  Nothing]
 
 instance HasAvroSchema ParentType where
diff --git a/test/Avro/Codec/TextSpec.hs b/test/Avro/Codec/TextSpec.hs
--- a/test/Avro/Codec/TextSpec.hs
+++ b/test/Avro/Codec/TextSpec.hs
@@ -22,7 +22,7 @@
 onlyTextSchema =
   let fld nm = Field nm [] Nothing Nothing
   in Record "test.contract.OnlyText" [] Nothing Nothing
-        [ fld "onlyTextValue" String Nothing
+        [ fld "onlyTextValue" String' Nothing
         ]
 
 instance HasAvroSchema OnlyText where
diff --git a/test/Avro/DefaultsSpec.hs b/test/Avro/DefaultsSpec.hs
--- a/test/Avro/DefaultsSpec.hs
+++ b/test/Avro/DefaultsSpec.hs
@@ -35,7 +35,7 @@
       msgSchema = schemaOf (undefined :: MaybeTest)
       fixedSchema = schemaOf (undefined :: FixedTag)
       defaults = fldDefault <$> fields msgSchema
-    in defaults `shouldBe` [ Just $ Ty.Union (V.fromList [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/JSONSpec.hs b/test/Avro/JSONSpec.hs
--- a/test/Avro/JSONSpec.hs
+++ b/test/Avro/JSONSpec.hs
@@ -6,9 +6,11 @@
 
 import Control.Monad (forM_)
 
-import qualified Data.Aeson           as Aeson
-import qualified Data.ByteString.Lazy as LBS
-import qualified Data.Map             as Map
+import           Control.Monad.Identity (Identity (..))
+import qualified Data.Aeson             as Aeson
+import qualified Data.ByteString        as BS
+import qualified Data.ByteString.Lazy   as LBS
+import qualified Data.Map               as Map
 
 import Data.Avro.Deriving
 import Data.Avro.EitherN
@@ -75,9 +77,15 @@
         , unionsRecords     = Left $ Foo { fooStuff = "stuff" }
         , unionsSameFields  = Left $ Foo { fooStuff = "foo stuff" }
         , unionsArrayAndMap = Left ["foo"]
+        , unionsOne         = Identity 42
         , unionsThree       = E3_1 37
         , unionsFour        = E4_2 "foo"
         , unionsFive        = E5_4 $ Foo { fooStuff = "foo stuff" }
+        , unionsSix        = E6_2 "foo"
+        , unionsSeven        = E7_6 6.28
+        , unionsEight        = E8_3 37
+        , unionsNine        = E9_1 37
+        , unionsTen        = E10_9 $ BS.pack [70, 79, 79, 66, 65, 82]
         }
       unionsExampleB = Unions
         { unionsScalars     = Right 37
@@ -87,9 +95,17 @@
                                           }
         , unionsSameFields  = Right $ NotFoo { notFooStuff = "not foo stuff" }
         , unionsArrayAndMap = Right $ Map.fromList [("a", 5)]
+        , unionsOne         = Identity 42
         , unionsThree       = E3_3 37
         , unionsFour        = E4_4 $ Foo { fooStuff = "foo stuff" }
         , unionsFive        = E5_5 $ NotFoo { notFooStuff = "not foo stuff" }
+        , unionsSix        = E6_6 6.28
+        , unionsSeven        = E7_7 False
+        , unionsEight        = E8_8 2.718
+        , unionsNine        = E9_9 $ BS.pack [70, 79, 79, 66, 65, 82]
+        , unionsTen        = E10_10 $ Bar { barStuff = "bar stuff",
+                                            barThings = Foo { fooStuff = "things" }
+                                          }
         }
   it "should roundtrip (unions)" $ do
     forM_ [unionsExampleA, unionsExampleB] $ \ msg ->
diff --git a/test/Avro/THUnionSpec.hs b/test/Avro/THUnionSpec.hs
--- a/test/Avro/THUnionSpec.hs
+++ b/test/Avro/THUnionSpec.hs
@@ -7,15 +7,18 @@
 
 import qualified Data.List.NonEmpty as NE
 
-import qualified Data.Aeson           as Aeson
+
+import           Control.Monad.Identity (Identity (..))
+import qualified Data.Aeson             as Aeson
 import           Data.Avro
 import           Data.Avro.Deriving
 import           Data.Avro.EitherN
-import qualified Data.Avro.Schema     as Schema
-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 qualified Data.Avro.Schema       as Schema
+import qualified Data.Avro.Types        as Avro
+import qualified Data.ByteString        as BS
+import qualified Data.ByteString.Lazy   as LBS
+import qualified Data.Map               as Map
+import qualified Data.Vector            as V
 
 import System.Directory (doesFileExist)
 
@@ -33,9 +36,15 @@
         , unionsRecords     = Left $ Foo { fooStuff = "stuff" }
         , unionsSameFields  = Left $ Foo { fooStuff = "more stuff" }
         , unionsArrayAndMap = Left ["foo"]
+        , unionsOne         = Identity 42
         , unionsThree       = E3_1 37
         , unionsFour        = E4_2 "foo"
         , unionsFive        = E5_4 $ Foo { fooStuff = "foo stuff" }
+        , unionsSix        = E6_2 "foo"
+        , unionsSeven        = E7_6 6.28
+        , unionsEight        = E8_3 37
+        , unionsNine        = E9_1 37
+        , unionsTen        = E10_9 $ BS.pack [70, 79, 79, 66, 65, 82]
         }
       objB = Unions
         { unionsScalars     = Right 42
@@ -45,9 +54,17 @@
                                           }
         , unionsSameFields  = Right $ NotFoo { notFooStuff = "different from Foo" }
         , unionsArrayAndMap = Right $ Map.fromList [("a", 5)]
+        , unionsOne         = Identity 42
         , unionsThree       = E3_3 37
         , unionsFour        = E4_4 $ Foo { fooStuff = "foo stuff" }
         , unionsFive        = E5_5 $ NotFoo { notFooStuff = "not foo stuff" }
+        , unionsSix        = E6_6 6.28
+        , unionsSeven        = E7_7 False
+        , unionsEight        = E8_8 2.718
+        , unionsNine        = E9_9 $ BS.pack [70, 79, 79, 66, 65, 82]
+        , unionsTen        = E10_10 $ Bar { barStuff = "bar stuff",
+                                            barThings = Foo { fooStuff = "things" }
+                                          }
         }
 
       field name schema def = Schema.Field name [] Nothing (Just Schema.Ascending) schema def
@@ -57,29 +74,36 @@
 
       foo    = named "haskell.avro.example.Foo"
       notFoo = named "haskell.avro.example.NotFoo"
+      bar = named "haskell.avro.example.Bar"
       expectedSchema = record "haskell.avro.example.Unions"
-        [ field "scalars"     (Schema.mkUnion (NE.fromList [Schema.String, Schema.Long])) scalarsDefault
-        , field "nullable"    (Schema.mkUnion (NE.fromList [Schema.Null, Schema.Int]))    nullableDefault
+        [ field "scalars"     (Schema.mkUnion (NE.fromList [Schema.String', Schema.Long'])) scalarsDefault
+        , field "nullable"    (Schema.mkUnion (NE.fromList [Schema.Null, Schema.Int']))    nullableDefault
         , field "records"     (Schema.mkUnion (NE.fromList [fooSchema, barSchema]))       Nothing
         , field "sameFields"  (Schema.mkUnion (NE.fromList [foo, notFooSchema]))          Nothing
         , field "arrayAndMap" (Schema.mkUnion (NE.fromList [array, map]))                 Nothing
 
-        , field "three" (Schema.mkUnion (NE.fromList [Schema.Int, Schema.String, Schema.Long]))              Nothing
-        , 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
+        , field "one"   (Schema.mkUnion (NE.fromList [Schema.Int']))                                          Nothing
+        , field "three" (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long']))              Nothing
+        , 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
+        , field "six"  (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long', foo, notFoo, Schema.Float])) Nothing
+        , field "seven"  (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long', foo, notFoo, Schema.Float, Schema.Boolean])) Nothing
+        , field "eight"  (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long', foo, notFoo, Schema.Float, Schema.Boolean, Schema.Double])) Nothing
+        , field "nine"  (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long', foo, notFoo, Schema.Float, Schema.Boolean, Schema.Double, Schema.Bytes'])) Nothing
+        , field "ten"  (Schema.mkUnion (NE.fromList [Schema.Int', Schema.String', Schema.Long', foo, notFoo, Schema.Float, Schema.Boolean, Schema.Double, Schema.Bytes', bar])) Nothing
         ]
-      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
+      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]
+      fooSchema = record "haskell.avro.example.Foo" [field "stuff" Schema.String' Nothing]
       barSchema = record "haskell.avro.example.Bar"
-        [ field "stuff"  Schema.String Nothing
+        [ field "stuff"  Schema.String' Nothing
         , field "things" (named "haskell.avro.example.Foo") Nothing
         ]
-      notFooSchema = record "haskell.avro.example.NotFoo" [field "stuff" Schema.String Nothing]
+      notFooSchema = record "haskell.avro.example.NotFoo" [field "stuff" Schema.String' Nothing]
 
-      array = Schema.Array { Schema.item = Schema.String }
-      map   = Schema.Map { Schema.values = Schema.Long }
+      array = Schema.Array { Schema.item = Schema.String' }
+      map   = Schema.Map { Schema.values = Schema.Long' }
 
   unionsSchemaFile <- runIO $ getFileName "test/data/unions.avsc" >>= LBS.readFile
   let Just unionsSchemaFromJSON = Aeson.decode unionsSchemaFile
diff --git a/test/Avro/ToAvroSpec.hs b/test/Avro/ToAvroSpec.hs
--- a/test/Avro/ToAvroSpec.hs
+++ b/test/Avro/ToAvroSpec.hs
@@ -33,10 +33,10 @@
 tmSchema =
   let fld nm = Field nm [] Nothing Nothing
    in Record "avro.haskell.test.TypesTestMessage" [] Nothing Nothing
-        [ fld "id" Long Nothing
-        , fld "name" String Nothing
-        , fld "timestamp" (mkUnion (Null :| [Long])) Nothing
-        , fld "foreignId" (mkUnion (Null :| [Long])) Nothing
+        [ fld "id" Long' Nothing
+        , fld "name" String' Nothing
+        , fld "timestamp" (mkUnion (Null :| [Long'])) Nothing
+        , fld "foreignId" (mkUnion (Null :| [Long'])) Nothing
         , fld "competence" (mkUnion (Null :| [Double])) Nothing
         , fld "relevance" (mkUnion (Null :| [Float])) Nothing
         , fld "severity" Float Nothing
diff --git a/test/Example1.hs b/test/Example1.hs
--- a/test/Example1.hs
+++ b/test/Example1.hs
@@ -23,11 +23,11 @@
 msSchema =
   Record "MyStruct" [] Nothing Nothing
       [ fld "enumOrString" eOrS (Just $ Ty.String "The Default")
-      , fld "intvalue" Long Nothing
+      , fld "intvalue" Long' Nothing
       ]
      where
      fld nm ty def = Field nm [] Nothing Nothing ty def
-     eOrS = mkUnion (meSchema :| [String])
+     eOrS = mkUnion (meSchema :| [String'])
 
 -- Encoding data, via the ToAvro class, requires both the routine that encodes
 -- data as well as the schema under which it is encoded.  The encoding and
diff --git a/test/data/unions-object-a.json b/test/data/unions-object-a.json
--- a/test/data/unions-object-a.json
+++ b/test/data/unions-object-a.json
@@ -16,9 +16,15 @@
   "arrayAndMap" : {
     "array" : ["foo"]
   },
+  "one": { "int": 42 },
   "three": { "int": 37 },
   "four": { "string": "foo" },
   "five": {
     "haskell.avro.example.Foo": { "stuff": "foo stuff" }
-  }
+  },
+  "six": { "string": "foo" },
+  "seven": { "float": 6.28 },
+  "eight": { "long": 37 },
+  "nine": { "int": 37 },
+  "ten": { "bytes": "FOOBAR" }
 }
diff --git a/test/data/unions-object-b.json b/test/data/unions-object-b.json
--- a/test/data/unions-object-b.json
+++ b/test/data/unions-object-b.json
@@ -21,11 +21,22 @@
   "arrayAndMap" : {
     "map" : { "a" : 5 }
   },
+  "one": { "int": 42 },
   "three": { "long": 37 },
   "four": {
     "haskell.avro.example.Foo": { "stuff" : "foo stuff" }
   },
   "five": {
     "haskell.avro.example.NotFoo": { "stuff": "not foo stuff" }
+  },
+  "six": { "float": 6.28 },
+  "seven": { "boolean": false },
+  "eight": { "double": 2.718 },
+  "nine": { "bytes": "FOOBAR" },
+  "ten": {
+    "haskell.avro.example.Bar": {
+      "stuff": "bar stuff",
+      "things": { "stuff": "things" }
+    }
   }
 }
diff --git a/test/data/unions.avsc b/test/data/unions.avsc
--- a/test/data/unions.avsc
+++ b/test/data/unions.avsc
@@ -54,8 +54,14 @@
         }
       ]
     },
+    { "name" : "one", "type" : ["int"] },
     { "name" : "three", "type" : ["int", "string", "long"] },
     { "name" : "four", "type" : ["int", "string", "long", "Foo"] },
-    { "name" : "five", "type" : ["int", "string", "long", "Foo", "NotFoo"] }
+    { "name" : "five", "type" : ["int", "string", "long", "Foo", "NotFoo"] },
+    { "name" : "six", "type" : ["int", "string", "long", "Foo", "NotFoo", "float"] },
+    { "name" : "seven", "type" : ["int", "string", "long", "Foo", "NotFoo", "float", "boolean"] },
+    { "name" : "eight", "type" : ["int", "string", "long", "Foo", "NotFoo", "float", "boolean", "double"] },
+    { "name" : "nine", "type" : ["int", "string", "long", "Foo", "NotFoo", "float", "boolean", "double", "bytes"] },
+    { "name" : "ten", "type" : ["int", "string", "long", "Foo", "NotFoo", "float", "boolean", "double", "bytes", "Bar"] }
   ]
 }
