diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Revision history for aeson-gadt-th
 
+## 0.2.5.2 - 2024-05-28
+
+* Loosen version bounds
+* Support GHC 9.8
+
 ## 0.2.5.1 - 2022-01-04
 
 * Remove dependency on `th-extras`. We were just using a reexport (under a
diff --git a/aeson-gadt-th.cabal b/aeson-gadt-th.cabal
--- a/aeson-gadt-th.cabal
+++ b/aeson-gadt-th.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.24
 name: aeson-gadt-th
-version: 0.2.5.1
+version: 0.2.5.2
 synopsis: Derivation of Aeson instances for GADTs
 category: JSON
 description: Template Haskell for generating ToJSON and FromJSON instances for GADTs. See <https://github.com/obsidiansystems/aeson-gadt-th/blob/master/README.md README.md> for examples.
@@ -20,13 +20,13 @@
 
 library
   exposed-modules: Data.Aeson.GADT.TH
-  build-depends: base >= 4.8 && < 4.16
-               , aeson >= 1.3 && < 1.6
+  build-depends: base >= 4.8 && < 4.20
+               , aeson >= 1.3 && < 2.3
                , containers >= 0.5 && < 0.7
                , dependent-sum >= 0.4 && < 0.8
-               , transformers >= 0.5 && < 0.6
-               , template-haskell >= 2.11.0 && < 2.18
-               , th-abstraction >= 0.4 && < 0.5
+               , transformers >= 0.5 && < 0.7
+               , template-haskell >= 2.11.0 && < 2.22
+               , th-abstraction >= 0.4 && < 0.8
   if impl(ghc < 8.2)
     build-depends: dependent-sum < 0.6.2.2
   hs-source-dirs: src
@@ -39,7 +39,7 @@
   build-depends: base
                , aeson
                , dependent-sum
-               , dependent-sum-template >= 0.1 && < 0.2
+               , dependent-sum-template >= 0.2 && < 0.3
                , dependent-map >= 0.3 && < 0.5
                , aeson-gadt-th
   default-language: Haskell2010
diff --git a/src/Data/Aeson/GADT/TH.hs b/src/Data/Aeson/GADT/TH.hs
--- a/src/Data/Aeson/GADT/TH.hs
+++ b/src/Data/Aeson/GADT/TH.hs
@@ -45,8 +45,17 @@
 import Data.Some (Some(..))
 import Language.Haskell.TH hiding (cxt)
 import Language.Haskell.TH.Datatype (ConstructorInfo(..), applySubstitution, datatypeCons, reifyDatatype, unifyTypes)
-import Language.Haskell.TH.Datatype.TyVarBndr (TyVarBndr_, tvName)
+import Language.Haskell.TH.Datatype.TyVarBndr (tvName)
 
+#if !MIN_VERSION_template_haskell(2,21,0)
+#if MIN_VERSION_th_abstraction(0,6,0)
+import Language.Haskell.TH.Datatype.TyVarBndr (TyVarBndrVis)
+#else
+import Language.Haskell.TH.Datatype.TyVarBndr (TyVarBndr_)
+type TyVarBndrVis = TyVarBndr_ ()
+#endif
+#endif
+
 #if MIN_VERSION_dependent_sum(0,5,0)
 #else
 pattern Some :: tag a -> Some tag
@@ -54,7 +63,7 @@
 #endif
 
 -- Do not export this type family, it must remain empty. It's used as a way to trick GHC into not unifying certain type variables.
-type family Skolem :: k -> k
+data family Skolem :: k -> k
 
 skolemize :: Set Name -> Type -> Type
 skolemize rigids t = case t of
@@ -143,7 +152,7 @@
   let constraints = map head . group . sort $ constraints' -- This 'head' is safe because 'group' returns a list of non-empty lists
   v <- newName "v"
   parser <- funD 'parseJSON
-    [ clause [varP v] (normalB [e| 
+    [ clause [varP v] (normalB [e|
         do (tag', _v') <- parseJSON $(varE v)
            $(caseE [|tag' :: String|] $ map pure matches ++ [wild])
       |]) []
@@ -238,10 +247,17 @@
           [InstanceD _ cxt (AppT _className (AppT (ConT _some) ityp)) _] -> do
             sub <- lift $ unifyTypes [ityp, tn]
             tellCxt $ applySubstitution sub cxt
-            return (ConP 'Some [VarP x], VarE x)
+            return ( ConP
+                       'Some
+#if MIN_VERSION_template_haskell(2,18,0)
+                       []
+#endif
+                       [VarP x]
+                   , VarE x
+                   )
           _ -> error $ "The following instances of " ++ show clsName ++ " for " ++ show (ppr [AppT (ConT ''Some) tn]) ++ " exist (rigids: " ++ unwords (map show $ Set.toList rigidVars) ++ "), and I don't know which to pick:\n" ++ unlines (map (show . ppr) insts)
       _ -> do
-        demandInstanceIfNecessary  
+        demandInstanceIfNecessary
         return (VarP x, VarE x)
   -- The singleton is special-cased because of
   -- https://downloads.haskell.org/ghc/8.10.1-rc1/docs/html/users_guide/8.10.1-notes.html#template-haskell
@@ -266,7 +282,7 @@
 -- its declaration, and the arity of the kind of type being defined (i.e. how many more arguments would
 -- need to be supplied in addition to the bound parameters in order to obtain an ordinary type of kind *).
 -- If the supplied 'Name' is anything other than a data or newtype, produces an error.
-tyConArity' :: Name -> Q ([TyVarBndr_ ()], Int)
+tyConArity' :: Name -> Q ([TyVarBndrVis], Int)
 tyConArity' n = reify n >>= return . \case
   TyConI (DataD _ _ ts mk _ _) -> (ts, maybe 0 kindArity mk)
   TyConI (NewtypeD _ _ ts mk _ _) -> (ts, maybe 0 kindArity mk)
