diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -43,3 +43,8 @@
 
 * Updated copyright dates.
 * Adjusted constraints on time.
+
+## 0.3.0.3  -- 2026-07-08
+
+* Updated copyright dates.
+* Adjusted constraints on `containers` and `time` for compatibility with GHC 9.14.x.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2017-2025 Henry Till
+Copyright (c) 2017-2026 Henry Till
 
 Permission to use, copy, modify, and/or distribute this software for any purpose
 with or without fee is hereby granted, provided that the above copyright notice
diff --git a/lens-toml-parser.cabal b/lens-toml-parser.cabal
--- a/lens-toml-parser.cabal
+++ b/lens-toml-parser.cabal
@@ -1,8 +1,6 @@
--- Initial lens-toml-parser.cabal generated by cabal init.  For further
--- documentation, see http://haskell.org/cabal/users-guide/
-
+cabal-version:       2.4
 name:                lens-toml-parser
-version:             0.3.0.2
+version:             0.3.0.3
 synopsis:            Lenses for toml-parser
 description:         This library provides lenses for toml-parser.
 license:             ISC
@@ -10,11 +8,10 @@
 author:              Henry Till
 maintainer:          henrytill@gmail.com
 homepage:            https://github.com/henrytill/lens-toml-parser
-copyright:           Copyright (c) 2017-2025, Henry Till
+copyright:           Copyright (c) 2017-2026, Henry Till
 category:            Language, Lenses
 build-type:          Simple
-cabal-version:       >=1.10
-tested-with:         GHC ==9.4.8 || ==9.6.6 || ==9.8.4 || ==9.10.1 || ==9.12.1
+tested-with:         GHC ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.3 || ==9.12.4 || ==9.14.1
 
 extra-source-files:
   .gitignore
@@ -33,7 +30,7 @@
   build-depends:       base        >=4.14 && <5
                      , profunctors >=5.2  && <5.7
                      , text        >=0.2  && <3
-                     , time        >=1.9  && <1.13 || >=1.14 && <1.15
+                     , time        >=1.9  && <1.13 || >=1.14 && <1.16
                      , toml-parser >=2.0  && <2.1
   hs-source-dirs:      src
   default-language:    Haskell2010
@@ -42,12 +39,13 @@
 test-suite tests
   type:                exitcode-stdio-1.0
   main-is:             Main.hs
-  build-depends:       base        >=4.14 && <5
-                     , containers  >=0.5  && <0.8
-                     , dwergaz     >=0.3  && <0.4
-                     , lens-family >=2.1  && <2.2
-                     , text        >=0.2  && <3
-                     , toml-parser >=2.0  && <2.1
+  build-depends:       base          >=4.14 && <5
+                     , containers    >=0.5  && <0.9
+                     , dwergaz       >=0.3  && <0.4
+                     , microlens     >=0.4  && <0.5
+                     , microlens-ghc >=0.4  && <0.5
+                     , text          >=0.2  && <3
+                     , toml-parser   >=2.0  && <2.1
                      , lens-toml-parser
   hs-source-dirs:      test
   default-language:    Haskell2010
diff --git a/src/Toml/Lens.hs b/src/Toml/Lens.hs
--- a/src/Toml/Lens.hs
+++ b/src/Toml/Lens.hs
@@ -9,28 +9,28 @@
 -- Lenses for <https://hackage.haskell.org/package/toml-parser toml-parser>.
 module Toml.Lens
   ( -- * Unannotated
-    _Table,
-    _List,
-    _Double,
-    _Integer,
-    _Text,
-    _Bool,
-    _ZonedTime,
-    _LocalTime,
-    _Day,
-    _TimeOfDay,
+    _Table
+  , _List
+  , _Double
+  , _Integer
+  , _Text
+  , _Bool
+  , _ZonedTime
+  , _LocalTime
+  , _Day
+  , _TimeOfDay
 
     -- * Annotated
-    _Table',
-    _List',
-    _Double',
-    _Integer',
-    _Text',
-    _Bool',
-    _ZonedTime',
-    _LocalTime',
-    _Day',
-    _TimeOfDay',
+  , _Table'
+  , _List'
+  , _Double'
+  , _Integer'
+  , _Text'
+  , _Bool'
+  , _ZonedTime'
+  , _LocalTime'
+  , _Day'
+  , _TimeOfDay'
   )
 where
 
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -6,9 +6,8 @@
 import Data.Map.Strict (Map)
 import Data.Text (Text)
 import qualified Data.Text.IO as TIO
-import Lens.Family2
-import Lens.Family2.Stock (at, just_, _2)
-import Lens.Family2.Unchecked (adapter)
+import Lens.Micro
+import Lens.Micro.GHC ()
 import System.Exit (exitFailure)
 import Test.Dwergaz
 import Toml (Table, Table' (..), Value, Value')
@@ -19,8 +18,8 @@
 allEqual (x : xs) = all (== x) xs
 allEqual [] = error "allEqual: empty list"
 
-table :: Adapter' (Table' a) (Map Text (a, Value' a))
-table = adapter unTable MkTable
+table :: Lens' (Table' a) (Map Text (a, Value' a))
+table = lens unTable (const MkTable)
   where
     unTable (MkTable t) = t
 
@@ -30,7 +29,7 @@
   (Value -> f Value) ->
   Table ->
   f Table
-valueAt k = under table . at k . just_ . _2
+valueAt k = table . at k . _Just . _2
 
 mapAt ::
   (Applicative f) =>
@@ -41,118 +40,118 @@
 mapAt k = valueAt k . _Table
 
 testTableKey :: Table -> Test
-testTableKey kv =
+testTableKey tbl =
   assertEqual
     "'key' from 'table' == Just \"value\""
     expected
     actual
   where
     expected = Just "value"
-    actual = kv ^? mapAt "table" . valueAt "key" . _Text
+    actual = tbl ^? mapAt "table" . valueAt "key" . _Text
 
 testTableZoo :: Table -> Test
-testTableZoo kv =
+testTableZoo tbl =
   assertEqual
     "'zoo' from 'table' == Nothing"
     expected
     actual
   where
     expected = Nothing
-    actual = kv ^? mapAt "table" . valueAt "zoo" . _Text
+    actual = tbl ^? mapAt "table" . valueAt "zoo" . _Text
 
 testTableSubtableKey :: Table -> Test
-testTableSubtableKey kv =
+testTableSubtableKey tbl =
   assertEqual
     "'key' from 'subtable' from 'table' == Just \"another value\""
     expected
     actual
   where
     expected = Just "another value"
-    actual = kv ^? mapAt "table" . mapAt "subtable" . valueAt "key" . _Text
+    actual = tbl ^? mapAt "table" . mapAt "subtable" . valueAt "key" . _Text
 
 testTableInlineNameFirst :: Table -> Test
-testTableInlineNameFirst kv =
+testTableInlineNameFirst tbl =
   assertEqual
     "'first' from 'name' from 'inline' from 'table' == \"Tom\""
     expected
     actual
   where
     expected = Just "Tom"
-    actual = kv ^? mapAt "table" . mapAt "inline" . mapAt "name" . valueAt "first" . _Text
+    actual = tbl ^? mapAt "table" . mapAt "inline" . mapAt "name" . valueAt "first" . _Text
 
 testTableInlinePointY :: Table -> Test
-testTableInlinePointY kv =
+testTableInlinePointY tbl =
   assertEqual
     "'y' from 'point' from 'inline' from 'table' == Just 2"
     expected
     actual
   where
     expected = Just 2
-    actual = kv ^? mapAt "table" . mapAt "inline" . mapAt "point" . valueAt "y" . _Integer
+    actual = tbl ^? mapAt "table" . mapAt "inline" . mapAt "point" . valueAt "y" . _Integer
 
 testStringBasicBasic :: Table -> Test
-testStringBasicBasic kv =
+testStringBasicBasic tbl =
   assertEqual
     "'basic' from 'basic' from 'string' == <some escaped nonsense>"
     expected
     actual
   where
     expected = Just "I'm a string. \"You can quote me\". Name\tJos\233\nLocation\tSF."
-    actual = kv ^? mapAt "string" . mapAt "basic" . valueAt "basic" . _Text
+    actual = tbl ^? mapAt "string" . mapAt "basic" . valueAt "basic" . _Text
 
 testStringMultiline :: Table -> Test
-testStringMultiline kv =
+testStringMultiline tbl =
   assertBool
     "'key1', 'key2', and 'key3' from 'multiline' from 'string' are all the same"
     (allEqual [actual1, actual2, actual3])
   where
-    actual1 = kv ^? mapAt "string" . mapAt "multiline" . valueAt "key1" . _Text
-    actual2 = kv ^? mapAt "string" . mapAt "multiline" . valueAt "key2" . _Text
-    actual3 = kv ^? mapAt "string" . mapAt "multiline" . valueAt "key3" . _Text
+    actual1 = tbl ^? mapAt "string" . mapAt "multiline" . valueAt "key1" . _Text
+    actual2 = tbl ^? mapAt "string" . mapAt "multiline" . valueAt "key2" . _Text
+    actual3 = tbl ^? mapAt "string" . mapAt "multiline" . valueAt "key3" . _Text
 
 testStringMultilineContinued :: Table -> Test
-testStringMultilineContinued kv =
+testStringMultilineContinued tbl =
   assertBool
     "'key1', 'key2', and 'key3' from 'continued' from 'multiline' from 'string' are all the same"
     (allEqual [actual1, actual2, actual3])
   where
-    actual1 = kv ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key1" . _Text
-    actual2 = kv ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key2" . _Text
-    actual3 = kv ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key3" . _Text
+    actual1 = tbl ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key1" . _Text
+    actual2 = tbl ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key2" . _Text
+    actual3 = tbl ^? mapAt "string" . mapAt "multiline" . mapAt "continued" . valueAt "key3" . _Text
 
 testArrayKey1 :: Table -> Test
-testArrayKey1 kv =
+testArrayKey1 tbl =
   assertEqual
     "'key1' from 'array' == [1, 2, 3]"
     expected
     actual
   where
     expected = [1, 2, 3]
-    actual = kv ^.. mapAt "array" . valueAt "key1" . _List . traverse . _Integer
+    actual = tbl ^.. mapAt "array" . valueAt "key1" . _List . traverse . _Integer
 
 tests :: [Table -> Test]
 tests =
-  [ testTableKey,
-    testTableZoo,
-    testTableSubtableKey,
-    testTableInlineNameFirst,
-    testTableInlinePointY,
-    testStringBasicBasic,
-    testStringMultiline,
-    testStringMultilineContinued,
-    testArrayKey1
+  [ testTableKey
+  , testTableZoo
+  , testTableSubtableKey
+  , testTableInlineNameFirst
+  , testTableInlinePointY
+  , testStringBasicBasic
+  , testStringMultiline
+  , testStringMultilineContinued
+  , testArrayKey1
   ]
 
 step :: Result -> (ShowS, Bool) -> (ShowS, Bool)
 step result (f, allPassed) =
-  ( showString (resultToString result) . showChar '\n' . f,
-    resultIsPassed result && allPassed
+  ( showString (resultToString result) . showChar '\n' . f
+  , resultIsPassed result && allPassed
   )
 
 runTests :: Table -> (String, Bool)
-runTests kv = (buildString mempty, passed)
+runTests tbl = (buildString mempty, passed)
   where
-    (buildString, passed) = foldr (step . runTest . ($ kv)) (mempty, True) tests
+    (buildString, passed) = foldr (step . runTest . ($ tbl)) (mempty, True) tests
 
 readTomlFile :: String -> IO Table
 readTomlFile file = TIO.readFile file >>= parse >>= handleError
