diff --git a/Criterion/IO.hs b/Criterion/IO.hs
--- a/Criterion/IO.hs
+++ b/Criterion/IO.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE Trustworthy #-}
-{-# LANGUAGE CPP, OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 -- |
 -- Module      : Criterion.IO
@@ -28,11 +28,7 @@
 
 import qualified Data.Aeson as Aeson
 import Data.Binary (Binary(..), encode)
-#if MIN_VERSION_binary(0, 6, 3)
 import Data.Binary.Get (runGetOrFail)
-#else
-import Data.Binary.Get (runGetState)
-#endif
 import Data.Binary.Put (putByteString, putWord16be, runPut)
 import qualified Data.ByteString.Char8 as B
 import Criterion.Types (Report(..))
@@ -81,7 +77,6 @@
 writeRecords :: Binary a => FilePath -> [a] -> IO ()
 writeRecords path rs = withFile path WriteMode (flip hPutRecords rs)
 
-#if MIN_VERSION_binary(0, 6, 3)
 readAll :: Binary a => Handle -> IO [a]
 readAll handle = do
   let go bs
@@ -90,16 +85,6 @@
                          Left (_, _, err) -> fail err
                          Right (bs', _, a) -> (a:) `fmap` go bs'
   go =<< L.hGetContents handle
-#else
-readAll :: Binary a => Handle -> IO [a]
-readAll handle = do
-  let go i bs
-         | L.null bs = return []
-         | otherwise =
-            let (a, bs', i') = runGetState get bs i
-             in (a:) `fmap` go i' bs'
-  go 0 =<< L.hGetContents handle
-#endif
 
 -- | On disk we store (name,version,reports), where
 --   'version' is the version of Criterion used to generate the file.
diff --git a/Criterion/Main/Options.hs b/Criterion/Main/Options.hs
--- a/Criterion/Main/Options.hs
+++ b/Criterion/Main/Options.hs
@@ -28,7 +28,7 @@
 import Criterion.Types (Config(..), Verbosity(..), measureAccessors,
                         measureKeys)
 import Data.Char (isSpace, toLower)
-import Data.Data (Data, Typeable)
+import Data.Data (Data)
 import Data.Int (Int64)
 import Data.List (isPrefixOf)
 import Data.Version (showVersion)
@@ -60,7 +60,7 @@
                  -- paths.
                | IPattern
                  -- ^ Same as 'Pattern', but case insensitive.
-               deriving (Eq, Ord, Bounded, Enum, Read, Show, Typeable, Data,
+               deriving (Eq, Ord, Bounded, Enum, Read, Show, Data,
                          Generic)
 
 -- | Execution mode for a benchmark program.
@@ -73,7 +73,7 @@
             -- analysing performance numbers.
           | Run Config MatchType [String]
             -- ^ Run and analyse the given benchmarks.
-          deriving (Eq, Read, Show, Typeable, Data, Generic)
+          deriving (Eq, Read, Show, Data, Generic)
 
 -- | Default benchmarking configuration.
 defaultConfig :: Config
diff --git a/Criterion/Report.hs b/Criterion/Report.hs
--- a/Criterion/Report.hs
+++ b/Criterion/Report.hs
@@ -38,8 +38,9 @@
 import Criterion.Monad (Criterion)
 import Criterion.Types
 import Data.Aeson (ToJSON (..), Value(..), object, (.=), Value)
+import qualified Data.Aeson.Key as Key
 import Data.Aeson.Text (encodeToLazyText)
-import Data.Data (Data, Typeable)
+import Data.Data (Data)
 import Data.Foldable (forM_)
 import GHC.Generics (Generic)
 import Paths_criterion (getDataFileName)
@@ -70,10 +71,6 @@
 import qualified Language.Javascript.Chart as Chart
 #endif
 
-#if MIN_VERSION_aeson(2,0,0)
-import qualified Data.Aeson.Key as Key
-#endif
-
 -- | Trim long flat tails from a KDE plot.
 tidyTails :: KDE -> KDE
 tidyTails KDE{..} = KDE { kdeType   = kdeType
@@ -225,7 +222,7 @@
        -> Value
 {-# SPECIALIZE vector :: T.Text -> U.Vector Double -> Value #-}
 vector name v = toJSON . map val . G.toList $ v where
-    val i = object [ toKey name .= i ]
+    val i = object [ Key.fromText name .= i ]
 
 
 -- | Render the elements of two vectors.
@@ -239,19 +236,10 @@
                        -> Value #-}
 vector2 name1 name2 v1 v2 = toJSON $ zipWith val (G.toList v1) (G.toList v2) where
     val i j = object
-        [ toKey name1 .= i
-        , toKey name2 .= j
+        [ Key.fromText name1 .= i
+        , Key.fromText name2 .= j
         ]
 
-#if MIN_VERSION_aeson(2,0,0)
-toKey :: T.Text -> Key.Key
-toKey = Key.fromText
-#else
-toKey :: T.Text -> T.Text
-toKey = id
-#endif
-
-
 -- | Attempt to include the contents of a file based on a search path.
 -- Returns 'B.empty' if the search fails or the file could not be read.
 --
@@ -275,7 +263,7 @@
 -- | A problem arose with a template.
 data TemplateException =
     TemplateNotFound FilePath   -- ^ The template could not be found.
-    deriving (Eq, Read, Show, Typeable, Data, Generic)
+    deriving (Eq, Read, Show, Data, Generic)
 
 instance Exception TemplateException
 
@@ -320,12 +308,6 @@
 #if defined(EMBED)
   `E.catch` \(e :: IOException) ->
     maybe (throwIO e)
-          (pure . TLE.decodeUtf8 . fromStrict)
+          (pure . TLE.decodeUtf8 . BL.fromStrict)
           (lookup fp dataFiles)
-  where
-# if MIN_VERSION_bytestring(0,10,0)
-    fromStrict = BL.fromStrict
-# else
-    fromStrict x = BL.fromChunks [x]
-# endif
 #endif
diff --git a/Criterion/Types.hs b/Criterion/Types.hs
--- a/Criterion/Types.hs
+++ b/Criterion/Types.hs
@@ -79,7 +79,7 @@
 import Data.Aeson (FromJSON(..), ToJSON(..))
 import Data.Binary (Binary(..), putWord8, getWord8)
 import Data.Binary.Orphans ()
-import Data.Data (Data, Typeable)
+import Data.Data (Data)
 import Data.Int (Int64)
 import Data.Map (Map)
 import GHC.Generics (Generic)
@@ -94,7 +94,7 @@
 data Verbosity = Quiet
                | Normal
                | Verbose
-                 deriving (Eq, Ord, Bounded, Enum, Read, Show, Typeable, Data,
+                 deriving (Eq, Ord, Bounded, Enum, Read, Show, Data,
                            Generic)
 
 -- | Top-level benchmarking configuration.
@@ -125,7 +125,7 @@
       -- benchmarks.
     , template     :: FilePath
       -- ^ Template file to use if writing a report.
-    } deriving (Eq, Read, Show, Typeable, Data, Generic)
+    } deriving (Eq, Read, Show, Data, Generic)
 
 
 -- | Outliers from sample data, calculated using the boxplot
@@ -141,7 +141,7 @@
     -- ^ Between 1.5 and 3 times the IQR above the third quartile.
     , highSevere  :: !Int64
     -- ^ More than 3 times the IQR above the third quartile.
-    } deriving (Eq, Read, Show, Typeable, Data, Generic)
+    } deriving (Eq, Read, Show, Data, Generic)
 
 instance FromJSON Outliers
 instance ToJSON Outliers
@@ -158,7 +158,7 @@
                    | Moderate   -- ^ Between 10% and 50%.
                    | Severe     -- ^ Above 50% (i.e. measurements
                                 -- are useless).
-                     deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+                     deriving (Eq, Ord, Read, Show, Data, Generic)
 
 instance FromJSON OutlierEffect
 instance ToJSON OutlierEffect
@@ -201,7 +201,7 @@
     -- ^ Brief textual description of effect.
     , ovFraction :: Double
     -- ^ Quantitative description of effect (a fraction between 0 and 1).
-    } deriving (Eq, Read, Show, Typeable, Data, Generic)
+    } deriving (Eq, Read, Show, Data, Generic)
 
 instance FromJSON OutlierVariance
 instance ToJSON OutlierVariance
@@ -221,7 +221,7 @@
     -- ^ Map from name to value of predictor coefficients.
   , regRSquare    :: St.Estimate St.ConfInt Double
     -- ^ R&#0178; goodness-of-fit estimate.
-  } deriving (Eq, Read, Show, Typeable, Generic)
+  } deriving (Eq, Read, Show, Generic)
 
 instance FromJSON Regression
 instance ToJSON Regression
@@ -246,7 +246,7 @@
     , anOutlierVar :: OutlierVariance
       -- ^ Description of the effects of outliers on the estimated
       -- variance.
-    } deriving (Eq, Read, Show, Typeable, Generic)
+    } deriving (Eq, Read, Show, Generic)
 
 instance FromJSON SampleAnalysis
 instance ToJSON SampleAnalysis
@@ -266,7 +266,7 @@
       kdeType   :: String
     , kdeValues :: U.Vector Double
     , kdePDF    :: U.Vector Double
-    } deriving (Eq, Read, Show, Typeable, Data, Generic)
+    } deriving (Eq, Read, Show, Data, Generic)
 
 instance FromJSON KDE
 instance ToJSON KDE
@@ -294,7 +294,7 @@
       -- ^ Analysis of outliers.
     , reportKDEs     :: [KDE]
       -- ^ Data for a KDE of times.
-    } deriving (Eq, Read, Show, Typeable, Generic)
+    } deriving (Eq, Read, Show, Generic)
 
 instance FromJSON Report
 instance ToJSON Report
@@ -315,7 +315,7 @@
 
 data DataRecord = Measurement Int String (V.Vector Measured)
                 | Analysed Report
-                deriving (Eq, Read, Show, Typeable, Generic)
+                deriving (Eq, Read, Show, Generic)
 
 instance Binary DataRecord where
   put (Measurement i n v) = putWord8 0 >> put i >> put n >> put v
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -7,11 +7,10 @@
 
 <a href="http://www.serpentine.com/criterion/fibber.html" target="_blank"><img src="www/fibber-screenshot.png"></a>
 
-To get started, read the <a
-href="http://www.serpentine.com/criterion/tutorial.html"
-target="_blank">online tutorial</a>, and take a look at the programs
-in the <a href="/examples"
-target="_blank">examples directory</a>.
+To get started, read the [online
+tutorial](http://www.serpentine.com/criterion/tutorial.html), and take a look
+at the programs in the [examples
+directory](https://github.com/haskell/criterion/tree/master/examples).
 
 # Get involved!
 
diff --git a/app/Options.hs b/app/Options.hs
--- a/app/Options.hs
+++ b/app/Options.hs
@@ -7,7 +7,7 @@
     , versionInfo
     ) where
 
-import Data.Data (Data, Typeable)
+import Data.Data (Data)
 import Data.Version (showVersion)
 import GHC.Generics (Generic)
 import Paths_criterion (version)
@@ -18,7 +18,7 @@
 data CommandLine
     = Report { jsonFile :: FilePath, outputFile :: FilePath, templateFile :: FilePath }
     | Version
-    deriving (Eq, Read, Show, Typeable, Data, Generic)
+    deriving (Eq, Read, Show, Data, Generic)
 
 reportOptions :: Parser CommandLine
 reportOptions = Report <$> measurements <*> outputFile <*> templateFile
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+1.6.4.0
+
+* Drop support for pre-8.0 versions of GHC.
+
 1.6.3.0
 
 * Remove a use of the partial `head` function within `criterion`.
diff --git a/criterion.cabal b/criterion.cabal
--- a/criterion.cabal
+++ b/criterion.cabal
@@ -1,5 +1,5 @@
 name:           criterion
-version:        1.6.3.0
+version:        1.6.4.0
 synopsis:       Robust, reliable performance measurement and analysis
 license:        BSD3
 license-file:   LICENSE
@@ -18,10 +18,6 @@
   examples/*.cabal
   examples/*.hs
 tested-with:
-  GHC==7.4.2,
-  GHC==7.6.3,
-  GHC==7.8.4,
-  GHC==7.10.3,
   GHC==8.0.2,
   GHC==8.2.2,
   GHC==8.4.4,
@@ -29,9 +25,11 @@
   GHC==8.8.4,
   GHC==8.10.7,
   GHC==9.0.2,
-  GHC==9.2.7,
-  GHC==9.4.5,
-  GHC==9.6.1
+  GHC==9.2.8,
+  GHC==9.4.8,
+  GHC==9.6.6,
+  GHC==9.8.2,
+  GHC==9.10.1
 
 data-files:
   templates/*.css
@@ -83,14 +81,12 @@
     Paths_criterion
 
   build-depends:
-    -- TODO: Eventually, we should bump the lower version bounds to >=2 so that
-    -- we can remove some CPP in Criterion.Report. See #247.
-    aeson >= 1 && < 2.3,
-    base >= 4.5 && < 5,
-    base-compat-batteries >= 0.10 && < 0.14,
-    binary >= 0.5.1.0,
+    aeson >= 2 && < 2.3,
+    base >= 4.9 && < 5,
+    base-compat-batteries >= 0.10 && < 0.15,
+    binary >= 0.8.3.0,
     binary-orphans >= 1.0.1 && < 1.1,
-    bytestring >= 0.9 && < 1.0,
+    bytestring >= 0.10.8.1 && < 1.0,
     cassava >= 0.3.0.0,
     code-page,
     containers,
@@ -115,18 +111,9 @@
     transformers-compat >= 0.6.4,
     vector >= 0.7.1,
     vector-algorithms >= 0.4
-  if impl(ghc < 7.6)
-    build-depends:
-      ghc-prim
-  if !impl(ghc >= 8.0)
-    build-depends:
-      fail == 4.9.*,
-      semigroups
 
   default-language: Haskell2010
-  ghc-options: -Wall -funbox-strict-fields
-  if impl(ghc >= 6.8)
-    ghc-options: -fwarn-tabs
+  ghc-options: -Wall -funbox-strict-fields -Wtabs
   if flag(fast)
     ghc-options: -O0
   else
@@ -151,14 +138,6 @@
     base-compat-batteries,
     criterion,
     optparse-applicative >= 0.13
-
-  if impl(ghc < 7.6)
-    build-depends:
-      ghc-prim
-
-  if !impl(ghc >= 8.0)
-    build-depends:
-      semigroups
 
 test-suite sanity
   type:                 exitcode-stdio-1.0
diff --git a/examples/ConduitVsPipes.hs b/examples/ConduitVsPipes.hs
--- a/examples/ConduitVsPipes.hs
+++ b/examples/ConduitVsPipes.hs
@@ -1,4 +1,4 @@
--- Contributed by Gabriel Gonzales as a test case for
+-- Contributed by Gabriella Gonzales as a test case for
 -- https://github.com/haskell/criterion/issues/35
 --
 -- The numbers reported by this benchmark can be made "more correct"
diff --git a/examples/Maps.hs b/examples/Maps.hs
--- a/examples/Maps.hs
+++ b/examples/Maps.hs
@@ -1,7 +1,6 @@
 -- Benchmark the cost of creating various types of map.
 
-{-# LANGUAGE CPP, FlexibleContexts, ScopedTypeVariables #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
 
 import Criterion.Main
 import Data.ByteString (ByteString, pack)
@@ -15,10 +14,6 @@
 import qualified Data.Vector.Generic as G
 import qualified Data.Vector.Unboxed as U
 
-#if !MIN_VERSION_bytestring(0,10,0)
-import Control.DeepSeq (NFData (..))
-#endif
-
 type V = U.Vector Int
 type B = V.Vector ByteString
 
@@ -85,8 +80,3 @@
 
 value :: Int
 value = 31337
-
-#if !MIN_VERSION_bytestring(0,10,0)
-instance NFData ByteString where
-    rnf bs = bs `seq` ()
-#endif
diff --git a/examples/Overhead.hs b/examples/Overhead.hs
--- a/examples/Overhead.hs
+++ b/examples/Overhead.hs
@@ -29,10 +29,7 @@
               ]
          else []
 
-#if !MIN_VERSION_base(4,6,0)
-getRTSStatsEnabled :: IO Bool
-getRTSStatsEnabled = return False
-#elif !MIN_VERSION_base(4,10,0)
+#if !MIN_VERSION_base(4,10,0)
 getRTSStatsEnabled :: IO Bool
 getRTSStatsEnabled = getGCStatsEnabled
 #endif
diff --git a/examples/criterion-examples.cabal b/examples/criterion-examples.cabal
--- a/examples/criterion-examples.cabal
+++ b/examples/criterion-examples.cabal
@@ -11,10 +11,6 @@
 build-type:    Simple
 cabal-version: >=1.10
 tested-with:
-  GHC==7.4.2,
-  GHC==7.6.3,
-  GHC==7.8.4,
-  GHC==7.10.3,
   GHC==8.0.2,
   GHC==8.2.2,
   GHC==8.4.4,
@@ -22,9 +18,11 @@
   GHC==8.8.4,
   GHC==8.10.7,
   GHC==9.0.2,
-  GHC==9.2.7,
-  GHC==9.4.5,
-  GHC==9.6.1
+  GHC==9.2.8,
+  GHC==9.4.8,
+  GHC==9.6.6,
+  GHC==9.8.2,
+  GHC==9.10.1
 
 flag conduit-vs-pipes
   default: True
@@ -38,7 +36,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     criterion
 
 executable conduit-vs-pipes
@@ -50,7 +48,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base >= 4.8 && < 5,
+    base >= 4.9 && < 5,
     conduit >= 1.2.13.1,
     criterion,
     pipes >= 4.3.5,
@@ -65,7 +63,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     bytestring,
     containers,
     criterion,
@@ -82,7 +80,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     criterion,
     criterion-measurement
 
@@ -92,7 +90,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     criterion
 
 executable good-read-file
@@ -101,7 +99,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     criterion
 
 executable extensible-cli
@@ -110,7 +108,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     base-compat-batteries,
     criterion,
     optparse-applicative
@@ -121,7 +119,7 @@
   default-language: Haskell2010
   ghc-options: -Wall -rtsopts
   build-depends:
-    base == 4.*,
+    base >= 4.9 && < 5,
     criterion
 
 -- Cannot uncomment due to https://github.com/haskell/cabal/issues/1725
@@ -133,6 +131,6 @@
 --   default-language: Haskell2010
 --   ghc-options: -Wall -rtsopts
 --   build-depends:
---     base == 4.*,
+--     base >= 4.9 && < 5,
 --     criterion,
 --     judy
diff --git a/tests/Cleanup.hs b/tests/Cleanup.hs
--- a/tests/Cleanup.hs
+++ b/tests/Cleanup.hs
@@ -1,8 +1,7 @@
 {-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
 
 import Criterion.Main (Benchmark, bench, nfIO)
 import Criterion.Types (Config(..), Verbosity(Quiet))
@@ -10,7 +9,6 @@
 import Control.Exception (Exception, try, throwIO)
 import Control.Monad (when)
 import Data.ByteString (ByteString)
-import Data.Typeable (Typeable)
 import Prelude ()
 import Prelude.Compat
 import System.Directory (doesFileExist, removeFile)
@@ -26,7 +24,7 @@
 instance NFData Handle where
     rnf !_ = ()
 
-data CheckResult = ShouldThrow | WrongData deriving (Show, Typeable)
+data CheckResult = ShouldThrow | WrongData deriving Show
 
 instance Exception CheckResult
 
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE CPP #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
 
 module Properties (tests) where
 
diff --git a/tests/Sanity.hs b/tests/Sanity.hs
--- a/tests/Sanity.hs
+++ b/tests/Sanity.hs
@@ -1,6 +1,4 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 import Criterion.Main (bench, bgroup, env, whnf)
 import System.Environment (getEnv, withArgs)
@@ -12,10 +10,6 @@
 import qualified Control.Exception as E
 import qualified Data.ByteString as B
 
-#if !MIN_VERSION_bytestring(0,10,0)
-import Control.DeepSeq (NFData (..))
-#endif
-
 fib :: Int -> Int
 fib = sum . go
   where go 0 = [0]
@@ -59,8 +53,3 @@
 getArgEnv =
   fmap words (getEnv "ARGS") `E.catch`
   \(_ :: E.SomeException) -> return []
-
-#if !MIN_VERSION_bytestring(0,10,0)
-instance NFData B.ByteString where
-    rnf bs = bs `seq` ()
-#endif
