diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.3.10
+
+- Support `aeson-2.0.0.0`
+
 # 0.3.9
 
 - Add `ToJSON/FromJSON Void`
diff --git a/aeson-compat.cabal b/aeson-compat.cabal
--- a/aeson-compat.cabal
+++ b/aeson-compat.cabal
@@ -1,101 +1,103 @@
-name:           aeson-compat
-version:        0.3.9
-synopsis:       Compatibility layer for aeson
-description:    Compatibility layer for @aeson@
-category:       Web
-homepage:       https://github.com/phadej/aeson-compat#readme
-bug-reports:    https://github.com/phadej/aeson-compat/issues
-author:         Oleg Grenrus <oleg.grenrus@iki.fi>
-maintainer:     Oleg Grenrus <oleg.grenrus@iki.fi>
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-cabal-version:  >= 1.10
+name:               aeson-compat
+version:            0.3.10
+synopsis:           Compatibility layer for aeson
+description:        Compatibility layer for @aeson@
+category:           Web
+homepage:           https://github.com/phadej/aeson-compat#readme
+bug-reports:        https://github.com/phadej/aeson-compat/issues
+author:             Oleg Grenrus <oleg.grenrus@iki.fi>
+maintainer:         Oleg Grenrus <oleg.grenrus@iki.fi>
+license:            BSD3
+license-file:       LICENSE
+build-type:         Simple
+cabal-version:      >=1.10
 tested-with:
   GHC ==7.6.3
    || ==7.8.4
    || ==7.10.3
    || ==8.0.2
    || ==8.2.2
-   || ==8.4.3
-   || ==8.6.1
+   || ==8.4.4
+   || ==8.6.5
+   || ==8.8.4
+   || ==8.10.4
+   || ==9.0.1
 
 extra-source-files:
-    CHANGELOG.md
-    README.md
+  CHANGELOG.md
+  README.md
 
 source-repository head
-  type: git
+  type:     git
   location: https://github.com/phadej/aeson-compat
 
 library
-  hs-source-dirs:
-      src
-  ghc-options: -Wall
+  hs-source-dirs:   src
+  ghc-options:      -Wall
   build-depends:
-      base                     >=4.6  && <4.13
-    , base-compat              >=0.6.0 && <0.11
-    , aeson                    >=0.7.0.6 && <1.5
-    , attoparsec               >=0.12 && <0.14
-    , attoparsec-iso8601       >=1.0.0.0 && <1.1
-    , bytestring               >=0.10 && <0.11
-    , containers               >=0.5  && <0.7
-    , exceptions               >=0.8  && <0.11
-    , hashable                 >=1.2  && <1.3
-    , scientific               >=0.3  && <0.4
-    , text                     >=1.2  && <1.3
-    , time                     >=1.4.0.1 && <1.9
-    , time-locale-compat       >=0.1.0.1 && <0.2
-    , unordered-containers     >=0.2  && <0.3
-    , vector                   >=0.10 && <0.13
-    , tagged                   >=0.7.3 && <0.9
+      aeson                 >=0.7.0.6 && <1.6 || >=2.0.0.0 && <2.1
+    , attoparsec            >=0.12    && <0.15
+    , attoparsec-iso8601    >=1.0.0.0 && <1.1
+    , base                  >=4.6     && <4.16
+    , base-compat           >=0.6.0   && <0.13
+    , bytestring            >=0.10    && <0.12
+    , containers            >=0.5     && <0.7
+    , exceptions            >=0.8     && <0.11
+    , hashable              >=1.2     && <1.4
+    , scientific            >=0.3     && <0.4
+    , tagged                >=0.7.3   && <0.9
+    , text                  >=1.2     && <1.3
+    , time                  >=1.4.0.1 && <1.12
+    , time-locale-compat    >=0.1.0.1 && <0.2
+    , unordered-containers  >=0.2     && <0.3
+    , vector                >=0.10    && <0.13
 
-  if !impl(ghc >= 8.0)
-    build-depends:
-      semigroups               >=0.18.5 && <0.19
-  if !impl(ghc >= 7.10)
+  if !impl(ghc >=8.0)
+    build-depends: semigroups >=0.18.5 && <0.20
+
+  if !impl(ghc >=7.10)
     build-depends:
-      nats                     >=1.1.2  && <1.2,
-      void                     >=0.7.2  && <0.8
+        nats  >=1.1.2 && <1.2
+      , void  >=0.7.2 && <0.8
 
-  exposed-modules:
-      Data.Aeson.Compat
+  exposed-modules:  Data.Aeson.Compat
   default-language: Haskell2010
 
 test-suite aeson-compat-test
-  type: exitcode-stdio-1.0
-  main-is: Tests.hs
-  hs-source-dirs:
-      test
-  ghc-options: -Wall
+  type:             exitcode-stdio-1.0
+  main-is:          Tests.hs
+  hs-source-dirs:   test
+  ghc-options:      -Wall
   build-depends:
-      base
-    , base-compat
-    , aeson
+      aeson
+    , aeson-compat
     , attoparsec
+    , base
+    , base-compat
+    , base-orphans          >=0.4.5  && <0.9
     , bytestring
     , containers
     , exceptions
     , hashable
+    , QuickCheck            >=2.10   && <2.15
+    , quickcheck-instances  >=0.3.16 && <0.4
     , scientific
+    , tagged
+    , tasty                 >=0.10   && <1.5
+    , tasty-hunit           >=0.9    && <0.11
+    , tasty-quickcheck      >=0.8    && <0.11
     , text
     , time
     , time-locale-compat
     , unordered-containers
     , vector
-    , tagged
-    , aeson-compat
-    , base-orphans          >=0.4.5 && <0.9
-    , tasty                 >=0.10 && <1.2
-    , tasty-hunit           >=0.9  && <0.11
-    , tasty-quickcheck      >=0.8  && <0.11
-    , QuickCheck            >=2.10 && <2.13
-    , quickcheck-instances  >=0.3.16  && <0.4
 
-  if !impl(ghc >= 8.0)
-    build-depends:
-      semigroups
-  if !impl(ghc >= 7.10)
+  if !impl(ghc >=8.0)
+    build-depends: semigroups
+
+  if !impl(ghc >=7.10)
     build-depends:
-      nats, void
+        nats
+      , void
+
   default-language: Haskell2010
diff --git a/src/Data/Aeson/Compat.hs b/src/Data/Aeson/Compat.hs
--- a/src/Data/Aeson/Compat.hs
+++ b/src/Data/Aeson/Compat.hs
@@ -98,7 +98,10 @@
 import Prelude.Compat
 
 import           Data.Aeson hiding
-  ((.:?), decode, decode', decodeStrict, decodeStrict'
+  ((.:?), (.:), decode, decode', decodeStrict, decodeStrict'
+#if MIN_VERSION_aeson (0,11,0)
+  , (.:!)
+#endif
 #if !MIN_VERSION_aeson (0,9,0)
   , eitherDecode, eitherDecode', eitherDecodeStrict, eitherDecodeStrict'
 #endif
@@ -107,6 +110,8 @@
 #endif
   )
 
+import qualified Data.Aeson as Aeson
+
 import           Data.Aeson.Parser (value, value')
 
 #if !MIN_VERSION_aeson (0,9,0)
@@ -117,10 +122,10 @@
 
 import           Control.Monad.Catch (MonadThrow (..), Exception)
 import           Data.Aeson.Types (Parser, modifyFailure, typeMismatch, defaultOptions)
-import           Data.ByteString as B
+import           Data.ByteString as BS
 import qualified Data.Scientific as Scientific
-import           Data.ByteString.Lazy as L
-import qualified Data.HashMap.Strict as H
+import           Data.ByteString.Lazy as LBS
+import qualified Data.HashMap.Strict as HM
 import           Data.Text as T
 import qualified Data.Text.Encoding as TE
 import           Data.Typeable (Typeable)
@@ -147,7 +152,7 @@
 import Data.Proxy          (Proxy (..))
 import Data.Tagged         (Tagged (..))
 
-import qualified Data.List.NonEmpty as NonEmpty
+import qualified Data.List.NonEmpty as NE
 import qualified Data.Vector        as V
 #endif
 
@@ -155,6 +160,11 @@
 import Data.Void (Void, absurd)
 #endif
 
+#if MIN_VERSION_aeson(2,0,0)
+import qualified Data.Aeson.Key as Key
+import qualified Data.Aeson.KeyMap as KM
+#endif
+
 import Data.Attoparsec.Number (Number (..))
 
 -- | Exception thrown by 'decode' - family of functions in this module.
@@ -170,21 +180,28 @@
 -- | Like original 'Data.Aeson.decode' but in arbitrary 'MonadThrow'.
 --
 -- Parse a top-level JSON value, i.e. also strings, numbers etc.
-decode :: (FromJSON a, MonadThrow m) => L.ByteString -> m a
+decode :: (FromJSON a, MonadThrow m) => LBS.ByteString -> m a
 decode = eitherAesonExc . eitherDecode
 
 -- | Like original 'Data.Aeson.decode'' but in arbitrary 'MonadThrow'.
-decode' :: (FromJSON a, MonadThrow m) => L.ByteString -> m a
+decode' :: (FromJSON a, MonadThrow m) => LBS.ByteString -> m a
 decode' = eitherAesonExc . eitherDecode'
 
 -- | Like original 'Data.Aeson.decodeStrict' but in arbitrary 'MonadThrow'.
-decodeStrict :: (FromJSON a, MonadThrow m) => B.ByteString -> m a
+decodeStrict :: (FromJSON a, MonadThrow m) => BS.ByteString -> m a
 decodeStrict = eitherAesonExc . eitherDecodeStrict
 
 -- | Like original 'Data.Aeson.decodeStrict'' but in arbitrary 'MonadThrow'.
-decodeStrict' :: (FromJSON a, MonadThrow m) => B.ByteString -> m a
+decodeStrict' :: (FromJSON a, MonadThrow m) => BS.ByteString -> m a
 decodeStrict' = eitherAesonExc . eitherDecodeStrict'
 
+(.:) :: (FromJSON a) => Object -> Text -> Parser a
+#if MIN_VERSION_aeson(2,0,0)
+obj .: key = obj Aeson..: Key.fromText key
+#else
+obj .: key = obj Aeson..: key
+#endif
+
 -- | Retrieve the value associated with the given key of an 'Object'.
 -- The result is 'Nothing' if the key is not present, or 'empty' if
 -- the value cannot be converted to the desired type.
@@ -195,7 +212,12 @@
 --
 -- This operator is consistent in @aeson >=0.7 && <0.11@
 (.:?) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
-obj .:? key = case H.lookup key obj of
+obj .:? key =
+#if MIN_VERSION_aeson(2,0,0)
+  case KM.lookup (Key.fromText key) obj of
+#else
+  case HM.lookup key obj of
+#endif
                 Nothing -> pure Nothing
                 Just v  ->
 #if MIN_VERSION_aeson(0,10,0)
@@ -207,11 +229,21 @@
 #endif
 {-# INLINE (.:?) #-}
 
-#if !MIN_VERSION_aeson(0,11,0)
 -- | Like '.:?', but the resulting parser will fail,
 -- if the key is present but is 'Null'.
 (.:!) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
-obj .:! key = case H.lookup key obj of
+#if MIN_VERSION_aeson(2,0,0)
+obj .:! key = obj Aeson..:! Key.fromText key
+#else
+#if MIN_VERSION_aeson(0,11,0)
+(.:!) = (Aeson..:!)
+#else
+obj .:! key =
+#if MIN_VERSION_aeson(2,0,0)
+  case KM.lookup (Key.fromText key) obj of
+#else
+  case HM.lookup key obj of
+#endif
                 Nothing -> pure Nothing
                 Just v  ->
 #if MIN_VERSION_aeson(0,10,0)
@@ -223,6 +255,7 @@
 #endif
 {-# INLINE (.:!) #-}
 #endif
+#endif
 
 #if !MIN_VERSION_aeson(0,9,0)
 -- From Parser.Internal
@@ -238,26 +271,26 @@
 jsonEOF' = value' <* A.skipSpace <* A.endOfInput
 
 -- | Like 'decode' but returns an error message when decoding fails.
-eitherDecode :: (FromJSON a) => L.ByteString -> Either String a
+eitherDecode :: (FromJSON a) => LBS.ByteString -> Either String a
 eitherDecode = eitherDecodeWith jsonEOF fromJSON
 {-# INLINE eitherDecode #-}
 
 -- | Like 'decodeStrict' but returns an error message when decoding fails.
-eitherDecodeStrict :: (FromJSON a) => B.ByteString -> Either String a
+eitherDecodeStrict :: (FromJSON a) => BS.ByteString -> Either String a
 eitherDecodeStrict = eitherDecodeStrictWith jsonEOF fromJSON
 {-# INLINE eitherDecodeStrict #-}
 
 -- | Like 'decode'' but returns an error message when decoding fails.
-eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
+eitherDecode' :: (FromJSON a) => LBS.ByteString -> Either String a
 eitherDecode' = eitherDecodeWith jsonEOF' fromJSON
 {-# INLINE eitherDecode' #-}
 
 -- | Like 'decodeStrict'' but returns an error message when decoding fails.
-eitherDecodeStrict' :: (FromJSON a) => B.ByteString -> Either String a
+eitherDecodeStrict' :: (FromJSON a) => BS.ByteString -> Either String a
 eitherDecodeStrict' = eitherDecodeStrictWith jsonEOF' fromJSON
 {-# INLINE eitherDecodeStrict' #-}
 
-eitherDecodeWith :: L.Parser Value -> (Value -> Result a) -> L.ByteString
+eitherDecodeWith :: L.Parser Value -> (Value -> Result a) -> LBS.ByteString
                  -> Either String a
 eitherDecodeWith p to s =
     case L.parse p s of
@@ -267,7 +300,7 @@
       L.Fail _ _ msg -> Left msg
 {-# INLINE eitherDecodeWith #-}
 
-eitherDecodeStrictWith :: A.Parser Value -> (Value -> Result a) -> B.ByteString
+eitherDecodeStrictWith :: A.Parser Value -> (Value -> Result a) -> BS.ByteString
                        -> Either String a
 eitherDecodeStrictWith p to s =
     case either Error to (A.parseOnly p s) of
@@ -356,7 +389,7 @@
       where
         go [(v,[])] = return v
         go (_ : xs) = go xs
-        go _        = fail $ "could not parse Version"
+        go _        = fail "could not parse Version"
 
 instance ToJSON Ordering where
   toJSON     = toJSON     . orderingToText
@@ -418,11 +451,11 @@
     parseJSON = fmap Const . parseJSON
 
 instance (ToJSON a) => ToJSON (NonEmpty a) where
-    toJSON = toJSON . NonEmpty.toList
+    toJSON = toJSON . NE.toList
     {-# INLINE toJSON #-}
 
 #if MIN_VERSION_aeson(0,10,0)
-    toEncoding = toEncoding . NonEmpty.toList
+    toEncoding = toEncoding . NE.toList
     {-# INLINE toEncoding #-}
 #endif
 
@@ -472,7 +505,7 @@
 -- | Decode a nested JSON-encoded string.
 withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
 withEmbeddedJSON _ innerParser (String txt) =
-    either fail innerParser $ eitherDecode (L.fromStrict $ TE.encodeUtf8 txt)
+    either fail innerParser $ eitherDecode (LBS.fromStrict $ TE.encodeUtf8 txt)
 withEmbeddedJSON name _ v = typeMismatch name v
 {-# INLINE withEmbeddedJSON #-}
 #endif
diff --git a/test/Tests.hs b/test/Tests.hs
--- a/test/Tests.hs
+++ b/test/Tests.hs
@@ -23,6 +23,10 @@
 
 import Data.Aeson.Compat
 
+#if MIN_VERSION_aeson(2,0,0)
+import Data.Aeson (Key)
+#endif
+
 main :: IO ()
 main = defaultMain $ testGroup "Tests"
   [ dotColonMark
@@ -87,5 +91,9 @@
 -- tests that symbols are exported
 -------------------------------------------------------------------------------
 
+#if MIN_VERSION_aeson(2,0,0)
+ex :: (Key, Value)
+#else
 ex :: (Text, Value)
+#endif
 ex = "foo" .= True
