diff --git a/Data/HashMap/Base.hs b/Data/HashMap/Base.hs
--- a/Data/HashMap/Base.hs
+++ b/Data/HashMap/Base.hs
@@ -58,6 +58,7 @@
     , fromListWith
 
       -- Internals used by the strict version
+    , Hash
     , Bitmap
     , bitmapIndexedOrFull
     , collision
diff --git a/Data/HashMap/Lazy.hs b/Data/HashMap/Lazy.hs
--- a/Data/HashMap/Lazy.hs
+++ b/Data/HashMap/Lazy.hs
@@ -17,10 +17,6 @@
 -- duplicate keys; each key can map to at most one value.  A 'HashMap'
 -- makes no guarantees as to the order of its elements.
 --
--- This map is strict in the keys and lazy in the values; keys are
--- evaluated to /weak head normal form/ before they are added to the
--- map.
---
 -- The implementation is based on /hash array mapped tries/.  A
 -- 'HashMap' is often faster than other tree-based set types,
 -- especially when key comparison is expensive, as in the case of
@@ -31,6 +27,9 @@
 -- operations are constant time.
 module Data.HashMap.Lazy
     (
+      -- * Strictness properties
+      -- $strictness
+
       HashMap
 
       -- * Construction
@@ -85,3 +84,9 @@
     ) where
 
 import Data.HashMap.Base as HM
+
+-- $strictness
+--
+-- This module satisfies the following strictness property:
+--
+-- * Key arguments are evaluated to WHNF
diff --git a/Data/HashMap/Strict.hs b/Data/HashMap/Strict.hs
--- a/Data/HashMap/Strict.hs
+++ b/Data/HashMap/Strict.hs
@@ -17,11 +17,6 @@
 -- duplicate keys; each key can map to at most one value.  A 'HashMap'
 -- makes no guarantees as to the order of its elements.
 --
--- This map is strict in both the keys and the values; keys and values
--- are evaluated to /weak head normal form/ before they are added to
--- the map.  Exception: the provided instances are the same as for the
--- lazy version of this module.
---
 -- The implementation is based on /hash array mapped tries/.  A
 -- 'HashMap' is often faster than other tree-based set types,
 -- especially when key comparison is expensive, as in the case of
@@ -32,6 +27,9 @@
 -- operations are constant time.
 module Data.HashMap.Strict
     (
+      -- * Strictness properties
+      -- $strictness
+
       HashMap
 
       -- * Construction
@@ -94,9 +92,18 @@
 import qualified Data.HashMap.Base as HM
 import Data.HashMap.Base hiding (
     adjust, fromList, fromListWith, insert, insertWith, intersectionWith,
-    lookupDefault, map, singleton, unionWith)
+    map, singleton, unionWith)
 import Data.HashMap.Unsafe (runST)
 
+-- $strictness
+--
+-- This module satisfies the following strictness properties:
+--
+-- 1. Key arguments are evaluated to WHNF;
+--
+-- 2. Keys and values are evaluated to WHNF before they are stored in
+--    the map.
+
 ------------------------------------------------------------------------
 -- * Construction
 
@@ -107,14 +114,6 @@
 ------------------------------------------------------------------------
 -- * Basic interface
 
--- | /O(log n)/ Return the value to which the specified key is mapped,
--- or the default value if this map contains no mapping for the key.
-lookupDefault :: (Eq k, Hashable k)
-              => v          -- ^ Default value to return.
-              -> k -> HashMap k v -> v
-lookupDefault !def k t = HM.lookupDefault def k t
-{-# INLINABLE lookupDefault #-}
-
 -- | /O(log n)/ Associate the specified value with the specified
 -- key in this map.  If this map previously contained a mapping for
 -- the key, the old value is replaced.
@@ -131,18 +130,18 @@
 -- >   where f new old = new + old
 insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v
            -> HashMap k v
-insertWith f k0 !v0 m0 = go h0 k0 v0 0 m0
+insertWith f k0 v0 m0 = go h0 k0 v0 0 m0
   where
     h0 = hash k0
-    go !h !k x !_ Empty = Leaf h (L k x)
+    go !h !k x !_ Empty = leaf h k x
     go h k x s (Leaf hy l@(L ky y))
         | hy == h = if ky == k
-                    then let !v' = f x y in Leaf h (L k v')
-                    else collision h l (L k x)
-        | otherwise = runST (two s h k x hy ky y)
+                    then leaf h k (f x y)
+                    else x `seq` (collision h l (L k x))
+        | otherwise = x `seq` runST (two s h k x hy ky y)
     go h k x s (BitmapIndexed b ary)
         | b .&. m == 0 =
-            let ary' = A.insert ary i $! Leaf h (L k x)
+            let ary' = A.insert ary i $! leaf h k x
             in bitmapIndexedOrFull (b .|. m) ary'
         | otherwise =
             let st   = A.index ary i
@@ -168,15 +167,17 @@
 unsafeInsertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
   where
     h0 = hash k0
-    go !h !k x !_ Empty = return $! Leaf h (L k x)
+    go !h !k x !_ Empty = return $! leaf h k x
     go h k x s (Leaf hy l@(L ky y))
         | hy == h = if ky == k
-                    then let !v' = f x y in return $! Leaf h (L k v')
-                    else return $! collision h l (L k x)
+                    then return $! leaf h k (f x y)
+                    else do
+                        let l' = x `seq` (L k x)
+                        return $! collision h l l'
         | otherwise = two s h k x hy ky y
     go h k x s t@(BitmapIndexed b ary)
         | b .&. m == 0 = do
-            ary' <- A.insertM ary i $! Leaf h (L k x)
+            ary' <- A.insertM ary i $! leaf h k x
             return $! bitmapIndexedOrFull (b .|. m) ary'
         | otherwise = do
             st <- A.indexM ary i
@@ -204,7 +205,7 @@
     h0 = hash k0
     go !_ !_ !_ Empty = Empty
     go h k _ t@(Leaf hy (L ky y))
-        | hy == h && ky == k = let !v' = f y in Leaf h (L k v')
+        | hy == h && ky == k = leaf h k (f y)
         | otherwise          = t
     go h k s t@(BitmapIndexed b ary)
         | b .&. m == 0 = t
@@ -240,7 +241,7 @@
     -- leaf vs. leaf
     go s t1@(Leaf h1 l1@(L k1 v1)) t2@(Leaf h2 l2@(L k2 v2))
         | h1 == h2  = if k1 == k2
-                      then Leaf h1 . L k1 $! f v1 v2
+                      then leaf h1 k1 (f v1 v2)
                       else collision h1 l1 l2
         | otherwise = goDifferentHash s h1 h2 t1 t2
     go s t1@(Leaf h1 (L k1 v1)) t2@(Collision h2 ls2)
@@ -322,7 +323,7 @@
 mapWithKey f = go
   where
     go Empty                 = Empty
-    go (Leaf h (L k v))      = let !v' = f k v in Leaf h $ L k v'
+    go (Leaf h (L k v))      = leaf h k (f k v)
     go (BitmapIndexed b ary) = BitmapIndexed b $ A.map' go ary
     go (Full ary)            = Full $ A.map' go ary
     go (Collision h ary)     =
@@ -357,7 +358,7 @@
 -- list contains duplicate mappings, the later mappings take
 -- precedence.
 fromList :: (Eq k, Hashable k) => [(k, v)] -> HashMap k v
-fromList = L.foldl' (\ m (k, v) -> HM.unsafeInsert k v m) empty
+fromList = L.foldl' (\ m (k, !v) -> HM.unsafeInsert k v m) empty
 {-# INLINABLE fromList #-}
 
 -- | /O(n*log n)/ Construct a map from a list of elements.  Uses
@@ -379,6 +380,11 @@
                      | otherwise -> go k ary (i+1) n
 {-# INLINABLE updateWith #-}
 
+-- | Append the given key and value to the array. If the key is
+-- already present, instead update the value of the key by applying
+-- the given function to the new and old value (in that order). The
+-- value is always evaluated to WHNF before being inserted into the
+-- array.
 updateOrSnocWith :: Eq k => (v -> v -> v) -> k -> v -> A.Array (Leaf k v)
                  -> A.Array (Leaf k v)
 updateOrSnocWith f k0 v0 ary0 = go k0 v0 ary0 0 (A.length ary0)
@@ -388,9 +394,20 @@
             -- Not found, append to the end.
             mary <- A.new_ (n + 1)
             A.copy ary 0 mary 0 n
-            A.write mary n (L k v)
+            let !l = v `seq` (L k v)
+            A.write mary n l
             return mary
         | otherwise = case A.index ary i of
             (L kx y) | k == kx   -> let !v' = f v y in A.update ary i (L k v')
                      | otherwise -> go k v ary (i+1) n
 {-# INLINABLE updateOrSnocWith #-}
+
+------------------------------------------------------------------------
+-- Smart constructors
+--
+-- These constructors make sure the value is in WHNF before it's
+-- inserted into the constructor.
+
+leaf :: Hash -> k -> v -> HashMap k v
+leaf h k !v = Leaf h (L k v)
+{-# INLINE leaf #-}
diff --git a/tests/Strictness.hs b/tests/Strictness.hs
--- a/tests/Strictness.hs
+++ b/tests/Strictness.hs
@@ -44,9 +44,6 @@
 pLookupDefaultKeyStrict :: Int -> HashMap Key Int -> Bool
 pLookupDefaultKeyStrict def m = isBottom $ HM.lookupDefault def bottom m
 
-pLookupDefaultValueStrict :: Key -> HashMap Key Int -> Bool
-pLookupDefaultValueStrict k m = isBottom $ HM.lookupDefault bottom k m
-
 pAdjustKeyStrict :: (Int -> Int) -> HashMap Key Int -> Bool
 pAdjustKeyStrict f m = isBottom $ HM.adjust f bottom m
 
@@ -72,6 +69,21 @@
     | HM.member k m = isBottom $ HM.insertWith (const2 bottom) k v m
     | otherwise     = isBottom $ HM.insertWith f k bottom m
 
+pFromListKeyStrict :: Bool
+pFromListKeyStrict = isBottom $ HM.fromList [(undefined :: Key, 1 :: Int)]
+
+pFromListValueStrict :: Bool
+pFromListValueStrict = isBottom $ HM.fromList [(K 1, undefined)]
+
+pFromListWithKeyStrict :: (Int -> Int -> Int) -> Bool
+pFromListWithKeyStrict f =
+    isBottom $ HM.fromListWith f [(undefined :: Key, 1 :: Int)]
+
+pFromListWithValueStrict :: [(Key, Int)] -> Bool
+pFromListWithValueStrict xs = case xs of
+    [] -> True
+    (x:_) -> isBottom $ HM.fromListWith (\ _ _ -> undefined) (x:xs)
+
 ------------------------------------------------------------------------
 -- * Test list
 
@@ -85,7 +97,6 @@
       , testProperty "member is key-strict" $ keyStrict HM.member
       , testProperty "lookup is key-strict" $ keyStrict HM.lookup
       , testProperty "lookupDefault is key-strict" pLookupDefaultKeyStrict
-      , testProperty "lookupDefault is value-strict" pLookupDefaultValueStrict
       , testProperty "! is key-strict" $ keyStrict (flip (HM.!))
       , testProperty "delete is key-strict" $ keyStrict HM.delete
       , testProperty "adjust is key-strict" pAdjustKeyStrict
@@ -94,6 +105,10 @@
       , testProperty "insert is value-strict" pInsertValueStrict
       , testProperty "insertWith is key-strict" pInsertWithKeyStrict
       , testProperty "insertWith is value-strict" pInsertWithValueStrict
+      , testProperty "fromList is key-strict" pFromListKeyStrict
+      , testProperty "fromList is value-strict" pFromListValueStrict
+      , testProperty "fromListWith is key-strict" pFromListWithKeyStrict
+      , testProperty "fromListWith is value-strict" pFromListWithValueStrict
       ]
     ]
 
diff --git a/unordered-containers.cabal b/unordered-containers.cabal
--- a/unordered-containers.cabal
+++ b/unordered-containers.cabal
@@ -1,5 +1,5 @@
 name:           unordered-containers
-version:        0.2.3.1
+version:        0.2.3.2
 synopsis:       Efficient hashing-based container types
 description:
   Efficient hashing-based container types.  The containers have been
