diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [0.4.0] - 2017-10-07
+
+### Changed
+- MKMap functions `fromList` and `toList` only take non-empty key lists
+
 ## [0.3.4] - 2017-10-04
 
 ### Fixed
diff --git a/src/Data/MultiKeyedMap.hs b/src/Data/MultiKeyedMap.hs
--- a/src/Data/MultiKeyedMap.hs
+++ b/src/Data/MultiKeyedMap.hs
@@ -27,9 +27,11 @@
 
 import qualified Data.Map.Strict as M
 import Data.Monoid (All(..))
-import qualified Data.List as L
+import Data.Semigroup ((<>))
+import Data.Foldable (foldl')
+import qualified Data.List.NonEmpty as NE
 import Data.Proxy (Proxy(..))
-import qualified Data.Tuple as T
+import qualified Data.Tuple as Tuple
 import qualified Text.Show as Show
 
 -- TODO: add time behaviour of functions to docstrings
@@ -107,18 +109,22 @@
 -- | Build a map from a list of key\/value pairs.
 fromList :: forall ik k v. (Ord k, Ord ik, Enum ik, Bounded ik)
          => (Proxy ik) -- ^ type of intermediate key
-         -> [([k], v)] -- ^ list of @(key, value)@
+         -> [(NE.NonEmpty k, v)] -- ^ list of @(key, value)@
          -> MKMap k v  -- ^ new map
 
 -- TODO: it’s probably better to implement with M.fromList
-fromList p = L.foldl' (\m (ks, v) -> newVal ks v m) (mkMKMap p)
+fromList p = foldl' (\m (ks, v) -> newVal ks v m) (mkMKMap p)
 
 -- | Convert the map to a list of key\/value pairs.
-toList :: MKMap k v -> [([k], v)]
+toList :: MKMap k v -> [(NE.NonEmpty k, v)]
 toList MKMap{keyMap, valMap} =
-  map (fmap (valMap M.!) . T.swap) . M.assocs . aggregateIk $ keyMap
-    where aggregateIk = M.foldlWithKey
-            (\m k ik -> M.insertWith (++) ik [k] m) mempty
+  map (fmap (valMap M.!) . Tuple.swap) . M.assocs . aggregateIk $ keyMap
+    where
+      aggregateIk :: forall k ik. (Ord ik, Enum ik)
+                  => M.Map k ik
+                  -> M.Map ik (NE.NonEmpty k)
+      aggregateIk = M.foldlWithKey
+            (\m k ik -> M.insertWith (<>) ik (pure k) m) mempty
 
 -- | “Unlink” keys that are pointing to the same value.
 --
@@ -146,7 +152,7 @@
 insert k v m@MKMap{keyMap, highestIk, valMap} =
   maybe ins upd $ M.lookup k keyMap
   where
-    ins = newVal [k] v m
+    ins = newVal (pure k) v m
     upd ik = MKMap { keyMap, highestIk, valMap = M.insert ik v valMap }
 
 
@@ -156,10 +162,9 @@
 -- Insert every key into the keyMap, increase the intermediate counter,
 -- insert the value at new intermediate counter.
 -- Overwrites all already existing keys!
-newVal :: (Ord k) => [k] -> v -> MKMap k v -> MKMap k v
-newVal [] _ m = m
+newVal :: (Ord k) => NE.NonEmpty k -> v -> MKMap k v -> MKMap k v
 newVal ks v MKMap{keyMap, highestIk, valMap} =
-  MKMap { keyMap = L.foldl' (\m k -> M.insert k next m) keyMap ks
+  MKMap { keyMap = foldl' (\m k -> M.insert k next m) keyMap ks
         , highestIk = next
         , valMap = M.insert next v valMap }
   where next = succ highestIk
diff --git a/src/Yarn/Lock/Parse.hs b/src/Yarn/Lock/Parse.hs
--- a/src/Yarn/Lock/Parse.hs
+++ b/src/Yarn/Lock/Parse.hs
@@ -22,6 +22,7 @@
 
 import Protolude hiding (try)
 import qualified Data.Char as Ch
+import qualified Data.List.NonEmpty as NE
 import qualified Data.Text as T
 import qualified Data.Map.Strict as M
 import Control.Monad (fail)
@@ -87,11 +88,11 @@
 -- @
 -- align-text@^0.1.1, align-text@^0.1.3:\\n
 -- @
-packageKeys :: Parser [YLT.PackageKey]
+packageKeys :: Parser (NE.NonEmpty YLT.PackageKey)
 packageKeys = label "package keys" $ do
   firstEls <- many (try $ lexeme $ packageKey ":," <* char ',')
   lastEl   <-                      packageKey ":"  <* char ':'
-  pure $ firstEls ++ [lastEl]
+  pure $ NE.fromList $ firstEls <> [lastEl]
 
 -- | A packageKey is @\<package-name\>\@\<semver\>@;
 --
diff --git a/src/Yarn/Lock/Types.hs b/src/Yarn/Lock/Types.hs
--- a/src/Yarn/Lock/Types.hs
+++ b/src/Yarn/Lock/Types.hs
@@ -9,6 +9,7 @@
 
 import Protolude hiding (try)
 import qualified Data.MultiKeyedMap as MKM
+import qualified Data.List.NonEmpty as NE
 
 -- | Yarn lockfile.
 --
@@ -33,7 +34,7 @@
   } deriving (Show, Eq, Ord)
 
 -- | Something with a list of 'PackageKey's pointing to it.
-data Keyed a = Keyed [PackageKey] a
+data Keyed a = Keyed (NE.NonEmpty PackageKey) a
   deriving (Show, Eq, Ord, Functor)
 
 -- | The actual npm package with dependencies and a way to download.
diff --git a/tests/TestMultiKeyedMap.hs b/tests/TestMultiKeyedMap.hs
--- a/tests/TestMultiKeyedMap.hs
+++ b/tests/TestMultiKeyedMap.hs
@@ -3,6 +3,7 @@
 
 import Protolude
 import qualified Data.List as List
+import qualified Data.List.NonEmpty as NE
 import Test.Tasty (TestTree)
 import Test.Tasty.TH
 import Test.Tasty.QuickCheck
@@ -12,31 +13,23 @@
 emptyMkm :: (Ord k) => MKM.MKMap k v
 emptyMkm = MKM.mkMKMap (Proxy :: Proxy Int)
 
-fromList :: [([Int], v)] -> MKM.MKMap Int v
+fromList :: [((NE.NonEmpty Int), v)] -> MKM.MKMap Int v
 fromList = MKM.fromList (Proxy :: Proxy Int)
 
 prop_equality :: Property
 prop_equality =
-  forAll (resize 5 arbitrary :: Gen [([Int], Int)])
-    $ \map1 -> forAll (resize 2 arbitrary :: Gen [([Int], Int)])
+  forAll (resize 5 arbitrary :: Gen [(NE.NonEmpty Int, Int)])
+    $ \map1 -> forAll (resize 2 arbitrary :: Gen [(NE.NonEmpty Int, Int)])
     $ \map2 ->
-        -- fromList drops empty keys, the right side would be different
-        keysNotEmpty map1 ==> keysNotEmpty map2 ==>
         -- equality of contents also applies to the MKM
         (map1 == map2) === (fromList map1 == fromList map2)
         -- force the contents to be the same, should always be equal
-  where
-    keysNotEmpty = all (\(ks, _) -> ks /= [])
 
 -- | inserting the same value is idempotent
 prop_insertIdempotent :: Int -> Int -> Property
 prop_insertIdempotent key val = do
   let insVal = MKM.insert key val
   (insVal emptyMkm) === (insVal (insVal emptyMkm))
-
-prop_fromList_emptyKeyList :: Int -> ([Int], Int) -> Property
-prop_fromList_emptyKeyList val el = do
-  fromList [([], val), el, ([], val)] === fromList [el]
 
 -- | inserting the same values in a different order
 -- results in the same map
diff --git a/tests/TestParse.hs b/tests/TestParse.hs
--- a/tests/TestParse.hs
+++ b/tests/TestParse.hs
@@ -3,6 +3,7 @@
 
 import Protolude
 import qualified Data.Map as Map
+import qualified Data.List.NonEmpty as NE
 import Test.Tasty (TestTree)
 import Test.Tasty.TH
 import Test.Tasty.HUnit
@@ -99,7 +100,8 @@
   let key = "foo@^1.3.4, bar@blafoo234, xnu@, @types/foo@@:\n"
   parseSuccess packageKeys key
     >>= \keys -> do
-      keys @?= [ PackageKey "foo" "^1.3.4"
+      keys @?= NE.fromList
+               [ PackageKey "foo" "^1.3.4"
                , PackageKey "bar" "blafoo234"
                -- yes, the version can be empty …
                , PackageKey "xnu" ""
diff --git a/yarn-lock.cabal b/yarn-lock.cabal
--- a/yarn-lock.cabal
+++ b/yarn-lock.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           yarn-lock
-version:        0.3.4
+version:        0.4.0
 synopsis:       Represent and parse yarn.lock files
 description:    Types and parser for the lock file format of the npm successor yarn. All modules should be imported qualified.
 category:       Data
@@ -28,7 +28,7 @@
       src
   ghc-options: -Wall
   build-depends:
-      base >= 4.9 && < 4.10
+      base == 4.9.*
     , containers
     , text
     , megaparsec == 5.*
@@ -52,7 +52,7 @@
       tests
   ghc-options: -Wall
   build-depends:
-      base >= 4.9 && < 4.10
+      base == 4.9.*
     , containers
     , text
     , megaparsec == 5.*
