diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Zip 2.2.1
+
+* Don't add Zip64 fields when copying entries from another archive
+  unless the source entry has them. [PR
+  128](https://github.com/mrkkrp/zip/pull/128).
+
 ## Zip 2.2.0
 
 * Skip the addition of Zip64 extra fields when sufficiently short strict
diff --git a/Codec/Archive/Zip/Internal.hs b/Codec/Archive/Zip/Internal.hs
--- a/Codec/Archive/Zip/Internal.hs
+++ b/Codec/Archive/Zip/Internal.hs
@@ -85,7 +85,7 @@
       EntrySelector
   | -- | Add an entry given its content as a string ByteString.
     StrictEntry CompressionMethod ByteString EntrySelector
-  | -- | Copy an entry form another archive without re-compression
+  | -- | Copy an entry from another archive without re-compression
     CopyEntry FilePath EntrySelector EntrySelector
   | -- | Change the name of the entry inside archive
     RenameEntry EntrySelector EntrySelector
@@ -854,7 +854,8 @@
       appendZip64 =
         case headerType of
           LocalHeader (StrictOrigin size) -> size >= ffffffff
-          LocalHeader _ -> True
+          LocalHeader (Borrowed ed) -> entryUsesZip64 ed
+          LocalHeader GenericOrigin -> True
           CentralDirHeader -> needsZip64 entry
       extraField =
         B.take 0xffff . runPut . putExtraField $
@@ -1143,6 +1144,10 @@
   any
     (>= ffffffff)
     [edOffset, edCompressedSize, edUncompressedSize]
+
+-- | Check if an entry has Zip64 extra fields.
+entryUsesZip64 :: EntryDescription -> Bool
+entryUsesZip64 EntryDescription {..} = M.member 1 edExtraField
 
 -- | Determine “version needed to extract” that should be written to the
 -- headers given the need of the Zip64 feature and the compression method.
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -394,7 +394,7 @@
 
 addEntrySpec :: SpecWith FilePath
 addEntrySpec =
-  context "when an entry is added" $
+  context "when an entry is added" $ do
     it "is there" $ \path ->
       property $ \m b s -> do
         info <- createArchive path $ do
@@ -403,6 +403,12 @@
           checkEntry' s
           (,) <$> getEntry s <*> (edCompression . (! s) <$> getEntries)
         info `shouldBe` (b, m)
+    it "does not add unnecessary zip64 extra fields" $ \path -> do
+      property $ \b s ->
+        fromIntegral (B.length b) < ffffffff ==> do
+          createArchive path (addEntry Store b s)
+          bytes <- B.drop (30 + rawSelectorLength s) <$> B.readFile path
+          bytes `shouldSatisfy` B.isPrefixOf b
 
 sinkEntrySpec :: SpecWith FilePath
 sinkEntrySpec =
@@ -438,7 +444,7 @@
 
 copyEntrySpec :: SpecWith FilePath
 copyEntrySpec =
-  context "when entry is copied form another archive" $
+  context "when entry is copied from another archive" $ do
     it "is there" $ \path ->
       property $ \m b s -> do
         let vpath = deriveVacant path
@@ -449,6 +455,14 @@
           checkEntry' s
           (,) <$> getEntry s <*> (edCompression . (! s) <$> getEntries)
         info `shouldBe` (b, m)
+    it "does not add unnecessary zip64 extra fields" $ \path -> do
+      property $ \b s ->
+        fromIntegral (B.length b) < ffffffff ==> do
+          let vpath = deriveVacant path
+          createArchive vpath $ addEntry Store b s
+          createArchive path $ copyEntry vpath s s
+          bytes <- B.drop (30 + rawSelectorLength s) <$> B.readFile path
+          bytes `shouldSatisfy` B.isPrefixOf b
 
 checkEntrySpec :: SpecWith FilePath
 checkEntrySpec = do
@@ -464,12 +478,11 @@
       it "does not pass the check" $ \path ->
         property $ \b s ->
           not (B.null b) ==> do
-            let nameLength = B.length . T.encodeUtf8 . getEntryName $ s
-                zip64Length =
+            let zip64Length =
                   if fromIntegral (B.length b) >= ffffffff
                     then 20
                     else 0
-                headerLength = 30 + nameLength + zip64Length
+                headerLength = 30 + rawSelectorLength s + zip64Length
             localFileHeaderOffset <- createArchive path $ do
               addEntry Store b s
               commit
@@ -495,8 +508,7 @@
       it "does not pass the check" $ \path ->
         property $ \b s ->
           not (B.null b) ==> do
-            let nameLength = B.length . T.encodeUtf8 . getEntryName $ s
-                headerLength = 50 + nameLength
+            let headerLength = 50 + rawSelectorLength s
             localFileHeaderOffset <- createArchive path $ do
               sinkEntry Store (C.yield b) s
               commit
@@ -921,3 +933,7 @@
 -- | Constrain the type of the argument monad to 'IO'.
 asIO :: IO a -> IO a
 asIO = id
+
+-- | Get the length in bytes of an encoded 'EntrySelector'.
+rawSelectorLength :: EntrySelector -> Int
+rawSelectorLength = B.length . T.encodeUtf8 . getEntryName
diff --git a/zip.cabal b/zip.cabal
--- a/zip.cabal
+++ b/zip.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.4
 name:            zip
-version:         2.2.0
+version:         2.2.1
 license:         BSD-3-Clause
 license-file:    LICENSE.md
 maintainer:      Mark Karpov <markkarpov92@gmail.com>
