diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@
 with IO and similar actions that often fail. Common examples are
 database queries and large file uploads.
 
-
 ## Documentation
 
 Please see haddocks for documentation.
@@ -24,7 +23,6 @@
 
 Ozgun Ataman, Soostone Inc
 
-
 ## Contributors
 
 Contributors, please list yourself here.
@@ -33,5 +31,5 @@
 - John Wiegley
 - Michael Snoyman
 - Michael Xavier
+- Toralf Wittner
 - Marco Zocca (@ocramz)
-
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,6 @@
+0.9.2.0
+* Add `retryOnError` [PR 44](https://github.com/Soostone/retry/pull/44)
+
 0.9.1.0
 * Add resumable retry/recover variants:
   * `resumeRetrying`
diff --git a/retry.cabal b/retry.cabal
--- a/retry.cabal
+++ b/retry.cabal
@@ -14,7 +14,7 @@
         case we should hang back for a bit and retry the query instead
         of simply raising an exception.
 
-version:             0.9.1.0
+version:             0.9.2.0
 synopsis:            Retry combinators for monadic actions that may fail
 license:             BSD3
 license-file:        LICENSE
@@ -41,6 +41,8 @@
     , ghc-prim
     , random               >= 1
     , transformers
+    , mtl
+    , mtl-compat
   hs-source-dirs:      src
   default-language:    Haskell2010
 
@@ -67,10 +69,11 @@
       , tasty
       , tasty-hunit
       , tasty-hedgehog
-      , hedgehog
+      , hedgehog           >= 1.0
       , stm
       , ghc-prim
       , mtl
+      , mtl-compat
     default-language: Haskell2010
 
     if flag(lib-Werror)
diff --git a/src/Control/Retry.hs b/src/Control/Retry.hs
--- a/src/Control/Retry.hs
+++ b/src/Control/Retry.hs
@@ -4,6 +4,7 @@
 {-# LANGUAGE MagicHash             #-}
 {-# LANGUAGE RankNTypes            #-}
 {-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE TupleSections         #-}
 {-# LANGUAGE UnboxedTuples         #-}
 {-# LANGUAGE ViewPatterns          #-}
 
@@ -59,6 +60,7 @@
     , skipAsyncExceptions
     , logRetries
     , defaultLogMsg
+    , retryOnError
     -- ** Resumable variants
     , resumeRetrying
     , resumeRetryingDynamic
@@ -93,8 +95,8 @@
 #endif
 import           Control.Monad
 import           Control.Monad.Catch
-import           Control.Monad.IO.Class
-import           Control.Monad.Trans.Class
+import           Control.Monad.Except
+import           Control.Monad.IO.Class as MIO
 import           Control.Monad.Trans.Maybe
 import           Control.Monad.Trans.State
 import           Data.List (foldl')
@@ -280,7 +282,7 @@
 -- | Apply policy and delay by its amount if it results in a retry.
 -- Return updated status.
 applyAndDelay
-    :: MonadIO m
+    :: MIO.MonadIO m
     => RetryPolicyM m
     -> RetryStatus
     -> m (Maybe RetryStatus)
@@ -814,6 +816,31 @@
   where
     iter = show $ rsIterNumber status
     nextMsg = if shouldRetry then "Retrying." else "Crashing."
+
+
+-------------------------------------------------------------------------------
+retryOnError
+    :: (Functor m, MonadIO m, MonadError e m)
+    => RetryPolicyM m
+    -- ^ Policy
+    -> (RetryStatus -> e -> m Bool)
+    -- ^ Should an error be retried?
+    -> (RetryStatus -> m a)
+    -- ^ Action to perform
+    -> m a
+retryOnError policy chk f = go defaultRetryStatus
+  where
+    go stat = do
+      res <- (Right <$> f stat) `catchError` (\e -> Left . (e, ) <$> chk stat e)
+      case res of
+        Right x -> return x
+        Left (e, True) -> do
+          mstat' <- applyAndDelay policy stat
+          case mstat' of
+            Just stat' -> do
+              go $! stat'
+            Nothing -> throwError e
+        Left (e, False) -> throwError e
 
 
 -------------------------------------------------------------------------------
diff --git a/test/Tests/Control/Retry.hs b/test/Tests/Control/Retry.hs
--- a/test/Tests/Control/Retry.hs
+++ b/test/Tests/Control/Retry.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE DeriveDataTypeable  #-}
 {-# LANGUAGE LambdaCase  #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
 module Tests.Control.Retry
     ( tests
     ) where
@@ -12,8 +13,9 @@
 import           Control.Concurrent.STM      as STM
 import qualified Control.Exception           as EX
 import           Control.Monad.Catch
+import           Control.Monad.Except
 import           Control.Monad.Identity
-import           Control.Monad.IO.Class
+import           Control.Monad.IO.Class      as MIO
 import           Control.Monad.Writer.Strict
 import           Data.Either
 import           Data.IORef
@@ -48,6 +50,7 @@
   , limitRetriesByCumulativeDelayTests
   , overridingDelayTests
   , resumableTests
+  , retryOnErrorTests
   ]
 
 
@@ -451,6 +454,22 @@
 
 
 -------------------------------------------------------------------------------
+retryOnErrorTests :: TestTree
+retryOnErrorTests = testGroup "retryOnError"
+  [ testCase "passes in the error type" $ do
+      errCalls <- newTVarIO []
+      let policy = limitRetries 2
+      let shouldWeRetry _retryStat e = do
+            liftIO (atomically (modifyTVar' errCalls (++ [e])))
+            return True
+      let action rs = (throwError ("boom" ++ show (rsIterNumber rs)))
+      res <- runExceptT (retryOnError policy shouldWeRetry action)
+      res @?= (Left "boom2" :: Either String ())
+      calls <- atomically (readTVar errCalls)
+      calls @?= ["boom0", "boom1", "boom2"]
+  ]
+
+-------------------------------------------------------------------------------
 nextStatusUsingPolicy :: RetryPolicyM IO -> RetryStatus -> IO RetryStatus
 nextStatusUsingPolicy policy status = do
   applyPolicy policy status >>= \case
@@ -513,7 +532,7 @@
 -------------------------------------------------------------------------------
 -- | Generate an arbitrary 'RetryPolicy' without any limits applied.
 genPolicyNoLimit
-    :: forall mg mr. (MonadGen mg, MonadIO mr)
+    :: forall mg mr. (MonadGen mg, MIO.MonadIO mr)
     => Range Int
     -> mg (RetryPolicyM mr)
 genPolicyNoLimit durationRange =
