diff --git a/Control/Monad/Primitive.hs b/Control/Monad/Primitive.hs
--- a/Control/Monad/Primitive.hs
+++ b/Control/Monad/Primitive.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE CPP, MagicHash, UnboxedTuples, TypeFamilies #-}
+{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
 
 -- |
 -- Module      : Control.Monad.Primitive
@@ -13,7 +14,8 @@
 
 module Control.Monad.Primitive (
   PrimMonad(..), RealWorld, primitive_,
-  primToPrim, primToIO, primToST,
+  PrimBase(..),
+  liftPrim, primToPrim, primToIO, primToST,
   unsafePrimToPrim, unsafePrimToIO, unsafePrimToST,
   unsafeInlinePrim, unsafeInlineIO, unsafeInlineST,
   touch
@@ -28,7 +30,27 @@
 #endif
 import GHC.ST     ( ST(..) )
 
--- | Class of primitive state-transformer monads
+import Control.Monad.Trans.Class (lift)
+import Data.Monoid (Monoid)
+
+import Control.Monad.Trans.Identity ( IdentityT)
+import Control.Monad.Trans.List     ( ListT    )
+import Control.Monad.Trans.Maybe    ( MaybeT   )
+import Control.Monad.Trans.Error    ( ErrorT, Error)
+import Control.Monad.Trans.Reader   ( ReaderT  )
+import Control.Monad.Trans.State    ( StateT   )
+import Control.Monad.Trans.Writer   ( WriterT  )
+import Control.Monad.Trans.RWS      ( RWST     )
+
+#if MIN_VERSION_transformers(0,4,0)
+import Control.Monad.Trans.Except   ( ExceptT  )
+#endif
+
+import qualified Control.Monad.Trans.RWS.Strict    as Strict ( RWST   )
+import qualified Control.Monad.Trans.State.Strict  as Strict ( StateT )
+import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
+
+-- | Class of monads which can perform primitive state-transformer actions
 class Monad m => PrimMonad m where
   -- | State token type
   type PrimState m
@@ -36,7 +58,12 @@
   -- | Execute a primitive operation
   primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
 
-
+-- | Class of primitive monads for state-transformer actions.
+--
+-- Unlike 'PrimMonad', this typeclass requires that the @Monad@ be fully
+-- expressed as a state transformer, therefore disallowing other monad
+-- transformers on top of the base @IO@ or @ST@.
+class PrimMonad m => PrimBase m where
   -- | Expose the internal structure of the monad
   internal :: m a -> State# (PrimState m) -> (# State# (PrimState m), a #)
 
@@ -51,51 +78,113 @@
 instance PrimMonad IO where
   type PrimState IO = RealWorld
   primitive = IO
-  internal (IO p) = p
   {-# INLINE primitive #-}
+instance PrimBase IO where
+  internal (IO p) = p
   {-# INLINE internal #-}
 
+instance PrimMonad m => PrimMonad (IdentityT m) where
+  type PrimState (IdentityT m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance PrimMonad m => PrimMonad (ListT m) where
+  type PrimState (ListT m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance PrimMonad m => PrimMonad (MaybeT m) where
+  type PrimState (MaybeT m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance (Error e, PrimMonad m) => PrimMonad (ErrorT e m) where
+  type PrimState (ErrorT e m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance PrimMonad m => PrimMonad (ReaderT r m) where
+  type PrimState (ReaderT r m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance PrimMonad m => PrimMonad (StateT s m) where
+  type PrimState (StateT s m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance (Monoid w, PrimMonad m) => PrimMonad (WriterT w m) where
+  type PrimState (WriterT w m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance (Monoid w, PrimMonad m) => PrimMonad (RWST r w s m) where
+  type PrimState (RWST r w s m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+
+#if MIN_VERSION_transformers(0,4,0)
+instance PrimMonad m => PrimMonad (ExceptT e m) where
+  type PrimState (ExceptT e m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+#endif
+
+instance PrimMonad m => PrimMonad (Strict.StateT s m) where
+  type PrimState (Strict.StateT s m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance (Monoid w, PrimMonad m) => PrimMonad (Strict.WriterT w m) where
+  type PrimState (Strict.WriterT w m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+instance (Monoid w, PrimMonad m) => PrimMonad (Strict.RWST r w s m) where
+  type PrimState (Strict.RWST r w s m) = PrimState m
+  primitive = lift . primitive
+  {-# INLINE primitive #-}
+
 instance PrimMonad (ST s) where
   type PrimState (ST s) = s
   primitive = ST
-  internal (ST p) = p
   {-# INLINE primitive #-}
+instance PrimBase (ST s) where
+  internal (ST p) = p
   {-# INLINE internal #-}
 
--- | Convert a 'PrimMonad' to another monad with the same state token.
-primToPrim :: (PrimMonad m1, PrimMonad m2, PrimState m1 ~ PrimState m2)
+-- | Lifts a 'PrimBase' into another 'PrimMonad' with the same underlying state
+-- token type.
+liftPrim
+  :: (PrimBase m1, PrimMonad m2, PrimState m1 ~ PrimState m2) => m1 a -> m2 a
+{-# INLINE liftPrim #-}
+liftPrim = primToPrim
+
+-- | Convert a 'PrimBase' to another monad with the same state token.
+primToPrim :: (PrimBase m1, PrimMonad m2, PrimState m1 ~ PrimState m2)
         => m1 a -> m2 a
 {-# INLINE primToPrim #-}
 primToPrim m = primitive (internal m)
 
--- | Convert a 'PrimMonad' with a 'RealWorld' state token to 'IO'
-primToIO :: (PrimMonad m, PrimState m ~ RealWorld) => m a -> IO a
+-- | Convert a 'PrimBase' with a 'RealWorld' state token to 'IO'
+primToIO :: (PrimBase m, PrimState m ~ RealWorld) => m a -> IO a
 {-# INLINE primToIO #-}
 primToIO = primToPrim
 
--- | Convert a 'PrimMonad' to 'ST'
-primToST :: PrimMonad m => m a -> ST (PrimState m) a
+-- | Convert a 'PrimBase' to 'ST'
+primToST :: PrimBase m => m a -> ST (PrimState m) a
 {-# INLINE primToST #-}
 primToST = primToPrim
 
--- | Convert a 'PrimMonad' to another monad with a possibly different state
+-- | Convert a 'PrimBase' to another monad with a possibly different state
 -- token. This operation is highly unsafe!
-unsafePrimToPrim :: (PrimMonad m1, PrimMonad m2) => m1 a -> m2 a
+unsafePrimToPrim :: (PrimBase m1, PrimMonad m2) => m1 a -> m2 a
 {-# INLINE unsafePrimToPrim #-}
 unsafePrimToPrim m = primitive (unsafeCoerce# (internal m))
 
--- | Convert any 'PrimMonad' to 'ST' with an arbitrary state token. This
+-- | Convert any 'PrimBase' to 'ST' with an arbitrary state token. This
 -- operation is highly unsafe!
-unsafePrimToST :: PrimMonad m => m a -> ST s a
+unsafePrimToST :: PrimBase m => m a -> ST s a
 {-# INLINE unsafePrimToST #-}
 unsafePrimToST = unsafePrimToPrim
 
--- | Convert any 'PrimMonad' to 'IO'. This operation is highly unsafe!
-unsafePrimToIO :: PrimMonad m => m a -> IO a
+-- | Convert any 'PrimBase' to 'IO'. This operation is highly unsafe!
+unsafePrimToIO :: PrimBase m => m a -> IO a
 {-# INLINE unsafePrimToIO #-}
 unsafePrimToIO = unsafePrimToPrim
 
-unsafeInlinePrim :: PrimMonad m => m a -> a
+unsafeInlinePrim :: PrimBase m => m a -> a
 {-# INLINE unsafeInlinePrim #-}
 unsafeInlinePrim m = unsafeInlineIO (unsafePrimToIO m)
 
diff --git a/Data/Primitive/Array.hs b/Data/Primitive/Array.hs
--- a/Data/Primitive/Array.hs
+++ b/Data/Primitive/Array.hs
@@ -29,7 +29,9 @@
 import Data.Data ( Data(..) )
 import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType )
 
+#if !(__GLASGOW_HASKELL__ >= 702)
 import Control.Monad.ST(runST)
+#endif
 
 -- | Boxed arrays
 data Array a = Array (Array# a) deriving ( Typeable )
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,11 @@
+## Changes in version 0.6
+
+ * Split PrimMonad into two classes to allow automatic lifting of primitive
+   operations into monad transformers. The `internal` operation has moved to the
+   `PrimBase` class.
+
+ * Fixed the test suite on older GHCs
+
 ## Changes in version 0.5.4.0
 
  * Changed primitive_ to work around an oddity with GHC's code generation
diff --git a/primitive.cabal b/primitive.cabal
--- a/primitive.cabal
+++ b/primitive.cabal
@@ -1,5 +1,5 @@
 Name:           primitive
-Version:        0.5.4.0
+Version:        0.6
 License:        BSD3
 License-File:   LICENSE
 
@@ -36,7 +36,9 @@
         Data.Primitive.Internal.Compat
         Data.Primitive.Internal.Operations
 
-  Build-Depends: base >= 4.3 && < 4.9, ghc-prim >= 0.2 && < 0.4
+  Build-Depends: base >= 4.3 && < 4.9
+               , ghc-prim >= 0.2 && < 0.5
+               , transformers >= 0.2 && < 0.5
 
   Ghc-Options: -O2 -Wall
 
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -15,7 +15,7 @@
             case writeArray arr 0 'B' of
                 IO f ->
                     case f realWorld# of
-                        _ -> ()
+                        (# _, _ #) -> ()
     c1 <- readArray arr 0
     return $! unit
     c2 <- readArray arr 0
