diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# unjson-0.15.3 (2020-05-05)
+* GHC 8.8 and 8.10 support
+
 # unjson-0.15.2.1 (2018-11-19)
 * GHC 8.6 support ([#12](https://github.com/scrive/unjson/pull/12)).
 * Documentation fixes
diff --git a/src/Data/Unjson.hs b/src/Data/Unjson.hs
--- a/src/Data/Unjson.hs
+++ b/src/Data/Unjson.hs
@@ -1,8 +1,4 @@
-
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ < 710
-{-# LANGUAGE OverlappingInstances #-}
-#endif
 
 -- | @Unjson@: bidirectional JSON (de)serialization with strong error
 -- reporting capabilities and automatic documentation generation.
@@ -187,7 +183,8 @@
 import qualified Data.HashMap.Lazy as LazyHashMap
 import Control.Exception
 
-import Control.Monad
+import Control.Monad hiding (fail)
+import Control.Monad.Fail (MonadFail (..))
 import Data.Bits
 import Data.Word
 import Data.Int
@@ -195,15 +192,7 @@
 import Data.List
 import qualified Text.ParserCombinators.ReadP as ReadP
 import Data.Char
-
-#if !MIN_VERSION_base(4,6,0)
-import Prelude hiding (catch)
-#endif
-
-#if !MIN_VERSION_base(4,8,0)
-import Control.Applicative
-import Data.Traversable
-#endif
+import Prelude hiding (fail)
 
 import qualified Text.PrettyPrint.HughesPJ as P
 
@@ -284,6 +273,8 @@
   return = pure
   Result a [] >>= m = m a
   Result _ es@(e:_) >>= _ = Result (throw e) es
+
+instance MonadFail Result where
   fail str = Result (throw anchoredMessage) [anchoredMessage]
     where anchoredMessage = Anchored mempty (Text.pack str)
 
@@ -1478,7 +1469,7 @@
 
 -- | Render only selected part of structure documentation. Path should
 -- point to a subtree, if it does not then Nothing is returned.
-renderForPath :: (Functor m, Monad m) => Path -> UnjsonDef a -> m String
+renderForPath :: (MonadFail m) => Path -> UnjsonDef a -> m String
 renderForPath path def = fmap P.render (renderDocForPath path def)
 
 -- | Renders documentation for a parser into a 'P.Doc'. See 'render'
@@ -1501,7 +1492,7 @@
 -- | Render only selected part of structure documentation as
 -- 'P.Doc'. Path should point to a subtree, if it does not then
 -- Nothing is returned.
-renderDocForPath :: (Monad m) => Path -> UnjsonDef a -> m P.Doc
+renderDocForPath :: (MonadFail m) => Path -> UnjsonDef a -> m P.Doc
 renderDocForPath path def = findNestedUnjson path def
 
 
@@ -1531,20 +1522,20 @@
   where
     s = renderDoc d
 
-findNestedUnjson :: (Monad m) => Path -> UnjsonDef a -> m P.Doc
+findNestedUnjson :: (MonadFail m) => Path -> UnjsonDef a -> m P.Doc
 findNestedUnjson (Path []) u = return (renderDoc u)
 findNestedUnjson (Path (PathElemIndex n : rest)) (TupleUnjsonDef d) = findNestedTupleUnjson n (Path rest) d
 findNestedUnjson (Path (PathElemIndex _ : rest)) (ArrayUnjsonDef _ _ _ _ d) = findNestedUnjson (Path rest) d
 findNestedUnjson (Path (PathElemKey k : rest)) (ObjectUnjsonDef d) = findNestedFieldUnjson k (Path rest) d
 findNestedUnjson _ _ = fail "cannot find crap"
 
-findNestedTupleUnjson :: (Monad m) => Int -> Path -> Ap (TupleFieldDef s) a -> m P.Doc
+findNestedTupleUnjson :: (MonadFail m) => Int -> Path -> Ap (TupleFieldDef s) a -> m P.Doc
 findNestedTupleUnjson n path (Ap (TupleFieldDef index _f d) _r) | n == index = findNestedUnjson path d
 findNestedTupleUnjson n path (Ap (TupleFieldDef _index _f _d) r) =
   findNestedTupleUnjson n path r
 findNestedTupleUnjson _ _ _ = fail "findNestedTupleUnjson"
 
-findNestedFieldUnjson :: (Monad m) => Text.Text -> Path -> Ap (FieldDef s) a -> m P.Doc
+findNestedFieldUnjson :: (MonadFail m) => Text.Text -> Path -> Ap (FieldDef s) a -> m P.Doc
 findNestedFieldUnjson key (Path []) (Ap f@(FieldReqDef k _ _ _d) _r) | k==key = return (renderField f)
 findNestedFieldUnjson key (Path []) (Ap f@(FieldOptDef k _ _ _d) _r) | k==key = return (renderField f)
 findNestedFieldUnjson key (Path []) (Ap f@(FieldDefDef k _ _ _ _d) _r) | k==key = return (renderField f)
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -2,6 +2,7 @@
 {-# OPTIONS_GHC -fno-warn-type-defaults #-}
 module Main where
 
+import Prelude hiding (fail)
 import qualified Data.Text as Text
 import qualified Data.ByteString.Lazy.Char8 as BSL
 import Data.Int
@@ -9,25 +10,17 @@
 import Data.Unjson
 import qualified Data.Aeson as Aeson
 import Data.Aeson ((.=))
-import Test.HUnit
 import Data.List
 import Data.Data
 import Data.Functor.Invariant
+import Control.Monad.Fail (MonadFail(fail))
+import Test.HUnit
 import qualified Data.HashMap.Strict as HashMap
 import qualified Data.HashMap.Lazy as LazyHashMap
 import qualified Data.Map as Map
 
 import System.Exit (ExitCode (..), exitWith)
 
-#if !MIN_VERSION_base(4,6,0)
-import Prelude hiding (catch)
-#endif
-
-#if !MIN_VERSION_base(4,8,0)
-import Control.Applicative
-import Data.Monoid
-#endif
-
 default (Text.Text, String, Int, Double)
 
 -- As an example we will use a hypothetical configuration data.
@@ -182,14 +175,14 @@
   let Result _val iss = parse unjsonKonfig json
   assertEqual "Number of issues in parsing" 3 (length iss)
   assertEqual "Hostname must be string error info is present"
-                (Anchored (Path [ PathElemKey "hostname"
-                                ]) "expected Text, encountered Number") (iss!!0)
+    (Anchored (Path [PathElemKey "hostname"])
+    "parsing Text failed, expected String, but encountered Number") (iss!!0)
   assertEqual "Port must be number error info is present"
-                (Anchored (Path [ PathElemKey "port"
-                                ]) "expected Integer, encountered Object") (iss!!1)
+    (Anchored (Path [ PathElemKey "port" ])
+    "parsing Integer failed, expected Number, but encountered Object") (iss!!1)
   assertEqual "Credentials must be object error info is present"
                 (Anchored (Path [ PathElemKey "credentials"
-                                ]) "Error in $: expected HashMap ~Text v, encountered String") (iss!!2)
+                                ]) "Error in $: parsing HashMap ~Text failed, expected Object, but encountered String") (iss!!2)
   return ()
 
 test_tuple_parsing :: Test
@@ -212,13 +205,17 @@
 
   let Result (_ :: (Integer, Integer, Text.Text)) iss'' = parse unjsonDef json
   assertEqual "Issues in parsing"
-                [ Anchored (Path [PathElemIndex 0]) "expected Integer, encountered String"
-                , Anchored (Path [PathElemIndex 1]) "expected Integer, encountered String"
-                , Anchored (Path [PathElemIndex 2]) "expected Text, encountered Number"
-                ] iss''
+    [ Anchored (Path [PathElemIndex 0])
+        "parsing Integer failed, expected Number, but encountered String"
+    , Anchored (Path [PathElemIndex 1])
+        "parsing Integer failed, expected Number, but encountered String"
+    , Anchored (Path [PathElemIndex 2])
+        "parsing Text failed, expected String, but encountered Number"
+    ] iss''
 
   let Result (_ :: (String, Text.Text)) iss''' = parse unjsonDef json
-  assertEqual "Array too long for 2-tuple" [Anchored mempty "cannot parse array of length 3 into tuple of size 2"] iss'''
+  assertEqual "Array too long for 2-tuple" [Anchored mempty
+    "cannot parse array of length 3 into tuple of size 2"] iss'''
 
   return ()
 
@@ -343,7 +340,8 @@
                  [ "value" .= (13 :: Int)
                  ]
     let Result _val iss = parse unjsonButThirteen json
-    assertEqual "Problem is reported" [Anchored (Path [PathElemKey "value"]) "13 is a bad luck number"] iss
+    assertEqual "Problem is reported" [Anchored (Path [PathElemKey "value"])
+      "13 is a bad luck number"] iss
     -- assertEqual "Just numerical_value present" (13) val
 
 unjsonEitherIntText :: UnjsonDef (Either Int Text.Text)
@@ -386,7 +384,8 @@
                  , "numerical_value" .= 12345
                  ]
     let Result _val iss = parse unjsonEitherIntText json
-    assertEqual "Problem when mode is missing" [Anchored (Path [PathElemKey "mode"]) "missing key"] iss
+    assertEqual "Problem when mode is missing" [Anchored (Path [PathElemKey "mode"])
+      "missing key"] iss
   do
     let json = Aeson.object
                  [ "mode" .= "something else"
@@ -436,7 +435,8 @@
                  [ "mode" .= "wrong"
                  ]
     let Result _val iss = parse unjsonEnumAB json
-    assertEqual "No problems" [Anchored (Path [PathElemKey "mode"]) "value 'wrong' is not one of the allowed for enumeration [A,B]"] iss
+    assertEqual "No problems" [Anchored (Path [PathElemKey "mode"])
+      "value 'wrong' is not one of the allowed for enumeration [A,B]"] iss
 
 
 data AutoAB = AutoA | AutoB
@@ -466,9 +466,10 @@
                  [ "AutoAB" .= "wrong"
                  ]
     let Result _val iss = parse unjsonAutoEnumAB json
-    assertEqual "No problems" [Anchored (Path [PathElemKey "AutoAB"]) "value 'wrong' is not one of the allowed for enumeration [AutoA,AutoB]"] iss
-    
+    assertEqual "No problems" [Anchored (Path [PathElemKey "AutoAB"])
+      "value 'wrong' is not one of the allowed for enumeration [AutoA,AutoB]"] iss
 
+
 test_update_from_serialization :: Test
 test_update_from_serialization = "test_update_from_serialization" ~: do
   let initial = Konfig
@@ -541,7 +542,8 @@
                ]
   let Result _ iss = update initial unjsonKonfig json
   assertEqual "Cannot reset mandatory field without default"
-                [Anchored (Path [PathElemKey "hostname"]) "expected Text, encountered Null"] iss
+    [Anchored (Path [PathElemKey "hostname"])
+      "parsing Text failed, expected String, but encountered Null"] iss
   return ()
 
 test_array_modes :: Test
@@ -571,7 +573,7 @@
   let Result _val0 iss0 = parse p0 json
   assertEqual "Does not parse value in strict array mode"
     [Anchored (Path [PathElemKey "hostname"])
-      "Error in $: expected Vector a, encountered String"] iss0
+      "Error in $: parsing Vector failed, expected Array, but encountered String"] iss0
   let Result val1 iss1 = parse p1 json
   assertEqual "No problems" [] iss1
   assertEqual "Accepts singel value in ArrayModeParseSingle" ["www.example.com"] val1
@@ -730,7 +732,8 @@
                ]
 
   let Result _val3 iss3 = parse unjsonPlainUnion json3
-  assertEqual "Cannot parse PlainUnionA" [Anchored (Path [PathElemKey "key1"]) "expected String, encountered Number"] iss3
+  assertEqual "Cannot parse PlainUnionA"
+    [Anchored (Path [PathElemKey "key1"]) "expected String, but encountered Number"] iss3
 
 
   -- choose PlainUnionB
diff --git a/unjson.cabal b/unjson.cabal
--- a/unjson.cabal
+++ b/unjson.cabal
@@ -1,6 +1,6 @@
 cabal-version:       1.18
 name:                unjson
-version:             0.15.2.1
+version:             0.15.3
 synopsis:            Bidirectional JSON parsing and generation.
 description:         Bidirectional JSON parsing and generation
                      with automatic documentation support.
@@ -15,8 +15,7 @@
 category:            Data
 build-type:          Simple
 extra-source-files:  README.md, CHANGELOG.md
-tested-with:         GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2,
-                     GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.2
+tested-with:         GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
 
 source-repository head
   type:     git
@@ -31,7 +30,7 @@
   exposed-modules:     Data.Unjson
   -- other-modules:
   -- other-extensions:
-  build-depends:       base >= 4.7 && < 4.13,
+  build-depends:       base >= 4.9 && < 5,
                        aeson >= 1.0 && < 1.5,
                        attoparsec,
                        bytestring >= 0.10,
