diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+0.3.4.3 (2019-12-15)
+ * #39: Improve Foldable instance
+
+0.3.4.2 (2018-11-21)
+ * #38: Fix stimes
+
 0.3.4.1 (2018-09-23)
  * Add support for containers-0.6.0.1 (shipped with GHC 8.6.1)
 
diff --git a/Data/IntMultiSet.hs b/Data/IntMultiSet.hs
--- a/Data/IntMultiSet.hs
+++ b/Data/IntMultiSet.hs
@@ -1,7 +1,4 @@
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ < 710
-{-# OPTIONS_GHC -fno-warn-amp #-}
-#endif
 #if __GLASGOW_HASKELL__
 {-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
 #endif
@@ -137,9 +134,9 @@
 #if __GLASGOW_HASKELL__ < 710
 import Data.Monoid (Monoid(..))
 #endif
-#if MIN_VERSION_base(4,11,0)
+#if MIN_VERSION_base(4,9,0)
 import qualified Data.List.NonEmpty (toList)
-import Data.Semigroup (Semigroup(..), stimesIdempotentMonoid)
+import Data.Semigroup (Semigroup(..))
 #endif
 import Data.Typeable ()
 import Data.IntMap.Strict (IntMap)
@@ -200,11 +197,14 @@
     mappend = union
     mconcat = unions
 
-#if MIN_VERSION_base(4,11,0)
+#if MIN_VERSION_base(4,9,0)
 instance Semigroup IntMultiSet where
     (<>) = union
     sconcat = unions . Data.List.NonEmpty.toList
-    stimes = stimesIdempotentMonoid
+    stimes n ms@(MS m)
+      | n <= 0    = empty
+      | n == 1    = ms
+      | otherwise = MS $ Map.map (* fromIntegral n) m
 #endif
 
 instance NFData IntMultiSet where
diff --git a/Data/MultiSet.hs b/Data/MultiSet.hs
--- a/Data/MultiSet.hs
+++ b/Data/MultiSet.hs
@@ -1,7 +1,5 @@
+{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ < 710
-{-# OPTIONS_GHC -fno-warn-amp #-}
-#endif
 #if __GLASGOW_HASKELL__
 {-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
 #endif
@@ -143,10 +141,13 @@
 #if __GLASGOW_HASKELL__ < 710
 import Data.Monoid (Monoid(..))
 #endif
-#if MIN_VERSION_base(4,11,0)
+#if MIN_VERSION_base(4,9,0)
 import qualified Data.List.NonEmpty (toList)
-import Data.Semigroup (Semigroup(..), stimesIdempotentMonoid)
+import Data.Semigroup (Semigroup(..))
+#if !MIN_VERSION_base(4,11,0)
+import Data.Semigroup (stimesMonoid)
 #endif
+#endif
 import Data.Typeable ()
 import qualified Data.Foldable as Foldable
 import Data.Map.Strict (Map)
@@ -200,16 +201,53 @@
     mappend = union
     mconcat = unions
 
-#if MIN_VERSION_base(4,11,0)
+#if MIN_VERSION_base(4,9,0)
 instance Ord a => Semigroup (MultiSet a) where
     (<>) = union
     sconcat = unions . Data.List.NonEmpty.toList
-    stimes = stimesIdempotentMonoid
+    stimes n ms@(MS m)
+      | n <= 0    = empty
+      | n == 1    = ms
+      | otherwise = MS $ Map.map (* fromIntegral n) m
 #endif
 
+-- | Note that 'elem' is slower than 'member'.
 instance Foldable.Foldable MultiSet where
-    foldr = fold
+    foldr = Data.MultiSet.foldr
+    foldl f z = Map.foldlWithKey repF z . unMS
+      where repF acc x 1 = f acc x
+            repF acc x n = repF (f acc x) x (n - 1)
+    foldr1 f = foldr1 f . toList
+    foldl1 f = foldl1 f . toList
 
+#if MIN_VERSION_base(4,11,0)
+    fold = Map.foldMapWithKey (\x n -> stimes n x) . unMS
+    foldMap f = Map.foldMapWithKey (\x n -> stimes n (f x)) . unMS
+#elif MIN_VERSION_base(4,9,0)
+    fold = Map.foldMapWithKey (\x n -> stimesMonoid n x) . unMS
+    foldMap f = Map.foldMapWithKey (\x n -> stimesMonoid n (f x)) . unMS
+#endif
+
+#if MIN_VERSION_base(4,6,0)
+    foldr' f z = Map.foldrWithKey' repF z . unMS
+      where repF x 1 !acc = f x acc
+            repF x n !acc = repF x (n - 1) (f x acc)
+    foldl' f z = Map.foldlWithKey' repF z . unMS
+      where repF !acc x 1 = f acc x
+            repF !acc x n = repF (f acc x) x (n - 1)
+#endif
+
+#if MIN_VERSION_base(4,8,0)
+    toList = toList
+    null = null
+    length = size
+    elem x = elem x . distinctElems
+    maximum = findMax
+    minimum = findMin
+    sum = Map.foldlWithKey' (\s x n -> s + (x * fromIntegral n)) 0 . unMS
+    product = Map.foldlWithKey' (\p x n -> p * (x ^ n)) 1 . unMS
+#endif
+
 instance NFData a => NFData (MultiSet a) where
     rnf = rnf . unMS
 
@@ -241,7 +279,7 @@
 
 -- | /O(n)/. The number of elements in the multiset.
 size :: MultiSet a -> Occur
-size = sum . Map.elems . unMS
+size = Map.foldl' (+) 0 . unMS
 
 -- | /O(1)/. The number of distinct elements in the multiset.
 distinctSize :: MultiSet a -> Occur
diff --git a/multiset.cabal b/multiset.cabal
--- a/multiset.cabal
+++ b/multiset.cabal
@@ -1,5 +1,5 @@
 name:             multiset
-version:          0.3.4.1
+version:          0.3.4.3
 author:           Twan van Laarhoven
 maintainer:       twanvl@gmail.com
 bug-reports:      https://github.com/twanvl/multiset/issues
@@ -13,6 +13,9 @@
 build-type:       Simple
 Cabal-version:    >= 1.10
 extra-source-files: include/Typeable.h CHANGELOG
+tested-with: GHC == 8.6.4, GHC == 8.4.4, GHC == 8.2.2, GHC == 8.0.2,
+             GHC == 7.10.3, GHC == 7.8.4, GHC == 7.6.3, GHC == 7.4.2,
+             GHC == 7.2.2, GHC == 7.0.4
 
 source-repository head
     type:     git
@@ -25,7 +28,7 @@
   include-dirs:       include
   default-extensions: CPP
   ghc-options:        -Wall
-  build-depends:      containers >= 0.5, base >= 4 && < 5, deepseq >=1.2 && <1.5
+  build-depends:      containers >= 0.5.4, base >= 4 && < 5, deepseq >=1.2 && <1.5
 
 test-suite doctests
   default-language:   Haskell2010
@@ -33,6 +36,20 @@
   ghc-options:        -threaded
   hs-source-dirs:     test
   main-is:            Main.hs
-  build-depends:      Glob
-                    , base >= 4 && < 5
+  build-depends:      base >= 4 && < 5
                     , doctest
+  if impl(ghc < 8.0)
+    buildable: False
+
+test-suite multiset-properties
+  default-language:   Haskell2010
+  type:               exitcode-stdio-1.0
+  ghc-options:        -threaded
+  hs-source-dirs:     test
+  main-is:            multiset-properties.hs
+  build-depends:      QuickCheck
+                    , base
+                    , checkers >= 0.5
+                    , multiset
+                    , tasty
+                    , tasty-quickcheck
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,18 +1,5 @@
-{-# LANGUAGE PackageImports #-}
-
 module Main (main) where
 
-import "Glob" System.FilePath.Glob (glob)
-import "doctest" Test.DocTest (doctest)
-
-includeDirs :: [String]
-includeDirs = ["include"]
-
-doctestWithIncludeDirs :: [String] -> IO ()
-doctestWithIncludeDirs fs = doctest (map ((++) "-I") includeDirs ++ fs)
-
-main :: IO ()
-main = do
-  glob "Data/**/*.hs" >>= doctestWithIncludeDirs
-  glob "test/**/*.hs" >>= doctestWithIncludeDirs
+import Test.DocTest (doctest)
 
+main = doctest ["-Iinclude", "Data/MultiSet.hs", "Data/IntMultiSet.hs"]
diff --git a/test/multiset-properties.hs b/test/multiset-properties.hs
new file mode 100644
--- /dev/null
+++ b/test/multiset-properties.hs
@@ -0,0 +1,19 @@
+import           Data.Monoid              (Sum(..))
+import           Data.MultiSet
+import           Test.QuickCheck          (Arbitrary(..))
+import qualified Test.QuickCheck.Classes
+import qualified Test.QuickCheck.Checkers
+import           Test.QuickCheck.Checkers (EqProp(..))
+import qualified Test.Tasty
+import qualified Test.Tasty.QuickCheck
+
+main = Test.Tasty.defaultMain
+  (uncurry Test.Tasty.QuickCheck.testProperties
+    (Test.QuickCheck.Classes.foldable
+      (undefined :: MultiSet (Integer, Integer, [Integer], Integer, Integer))))
+
+instance (Arbitrary a, Ord a) => Arbitrary (MultiSet a) where
+  arbitrary = fromList <$> arbitrary
+
+instance Eq a => EqProp (MultiSet a) where
+  (=-=) = Test.QuickCheck.Checkers.eq
