diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for primitive-atomic
 
+## 0.1.0.2 -- 2024-03-26
+
+* Support primitive-unlifted >= 2.1, drop older primitive-unlifted support.
+
 ## 0.1.0.0 -- 2019-04-25
 
 * First version.
diff --git a/primitive-atomic.cabal b/primitive-atomic.cabal
--- a/primitive-atomic.cabal
+++ b/primitive-atomic.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.2
 name: primitive-atomic
-version: 0.1.0.1
+version: 0.1.0.2
 synopsis: Wrappers for primops around atomic operations
 homepage: https://github.com/andrewthad/primitive-atomic
 license: BSD-3-Clause
@@ -21,8 +21,8 @@
     Data.Primitive.PrimArray.Atomic
   build-depends:
     , base >=4.11.1 && <5
-    , primitive >= 0.7 && <0.8
-    , primitive-unlifted >= 0.1 && <0.2
+    , primitive >= 0.7 && <0.10
+    , primitive-unlifted >= 2.1
   hs-source-dirs: src
   default-language: Haskell2010
   ghc-options: -Wall
diff --git a/src/Data/Primitive/Unlifted/Atomic.hs b/src/Data/Primitive/Unlifted/Atomic.hs
--- a/src/Data/Primitive/Unlifted/Atomic.hs
+++ b/src/Data/Primitive/Unlifted/Atomic.hs
@@ -8,10 +8,11 @@
   ) where
 
 import Control.Monad.Primitive (PrimMonad,PrimState,primitive)
-import Data.Primitive.Unlifted.Array (MutableUnliftedArray(..))
-import Data.Primitive.Unlifted.Class (PrimUnlifted,Unlifted,toUnlifted#,fromUnlifted#)
-import GHC.Exts (Any,MutableArrayArray#,MutableArray#,ArrayArray#,Int(I#))
-import GHC.Exts (casArray#,isTrue#,(==#),unsafeCoerce#)
+import Data.Primitive.Unlifted.Array (MutableUnliftedArray,MutableUnliftedArray_(..))
+import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(..))
+import Data.Primitive.Unlifted.Class (PrimUnlifted,toUnlifted#,fromUnlifted#)
+import GHC.Exts (Int(I#))
+import GHC.Exts (casArray#,isTrue#,(==#))
 
 -- | Given an array, an offset, the expected old value,
 -- and the new value, perform an atomic compare and swap i.e. write
@@ -23,20 +24,20 @@
 -- resources, have good guarantees about pointer equality. With these
 -- types, this function is much easier to reason about than @casArray@.
 casUnliftedArray :: forall m a. (PrimMonad m, PrimUnlifted a)
-  => MutableUnliftedArray (PrimState m) a -- ^ prim array
+  => MutableUnliftedArray (PrimState m) a -- ^ array
   -> Int -- ^ index
   -> a -- ^ expected old value
   -> a -- ^ new value
   -> m (Bool,a)
 {-# INLINE casUnliftedArray #-}
-casUnliftedArray (MutableUnliftedArray arr#) (I# i#) old new =
+casUnliftedArray (MutableUnliftedArray (MutableUnliftedArray# arr#)) (I# i#) old new =
   -- All of this unsafeCoercing is really nasty business. This will go away
   -- once https://github.com/ghc-proposals/ghc-proposals/pull/203 happens.
   -- Also, this is unsound if the result is immidiately consumed by
   -- the FFI.
   primitive $ \s0 ->
-    let !uold = (unsafeCoerce# :: Unlifted a -> Any) (toUnlifted# old)
-        !unew = (unsafeCoerce# :: Unlifted a -> Any) (toUnlifted# new)
-     in case casArray# ((unsafeCoerce# :: MutableArrayArray# (PrimState m) -> MutableArray# (PrimState m) Any) arr#) i# uold unew s0 of
-          (# s1, n, ur #) -> (# s1, (isTrue# (n ==# 0# ),fromUnlifted# ((unsafeCoerce# :: Any -> Unlifted a) ur)) #)
+    let !uold = toUnlifted# old
+        !unew = toUnlifted# new
+     in case casArray# arr# i# uold unew s0 of
+          (# s1, n, ur #) -> (# s1, (isTrue# (n ==# 0# ),fromUnlifted# ur) #)
 
