diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
 [The latest version of this document is on GitHub.](https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md)
 
+0.12.1
+------
+
+### Bug fixes
+
+- Prevent double-escaping in link segments
+  ([#835](https://github.com/haskell-servant/servant/issues/835)
+   [#878](https://github.com/haskell-servant/servant/pull/878))
+
 0.12
 ---
 
@@ -59,7 +68,7 @@
 - Lower `:>` and `:<|>` infix precedence to 4 and 3 respectively
   ([#761](https://github.com/haskell-servant/servant/issues/761))
 
-  This should affect you, except if you define your own infix operators
+  This shouldn't affect you, except if you define your own infix operators
   for Servant type-level DSL.
 
 ### Other changes
diff --git a/servant.cabal b/servant.cabal
--- a/servant.cabal
+++ b/servant.cabal
@@ -1,5 +1,5 @@
 name:                servant
-version:             0.12
+version:             0.12.1
 synopsis:            A family of combinators for defining webservices APIs
 description:
   A family of combinators for defining webservices APIs and serving them
@@ -70,7 +70,7 @@
     , case-insensitive      >= 1.2  && < 1.3
     , http-api-data         >= 0.3  && < 0.4
     , http-media            >= 0.4  && < 0.8
-    , http-types            >= 0.8  && < 0.11
+    , http-types            >= 0.8  && < 0.12
     , natural-transformation >= 0.4 && < 0.5
     , mtl                   >= 2.0  && < 2.3
     , mmorph                >= 1    && < 1.2
diff --git a/src/Servant/Utils/Links.hs b/src/Servant/Utils/Links.hs
--- a/src/Servant/Utils/Links.hs
+++ b/src/Servant/Utils/Links.hs
@@ -126,12 +126,24 @@
 -- The only way of constructing a 'Link' is using 'safeLink', which means any
 -- 'Link' is guaranteed to be part of the mentioned API.
 data Link = Link
-  { _segments :: [String]   -- ^ Segments of "foo/bar" would be ["foo", "bar"]
+  { _segments    :: [Escaped]
   , _queryParams :: [Param]
   } deriving Show
 
+newtype Escaped = Escaped String
+
+escaped :: String -> Escaped
+escaped = Escaped . escapeURIString isUnreserved
+
+getEscaped :: Escaped -> String
+getEscaped (Escaped s) = s
+
+instance Show Escaped where
+    showsPrec d (Escaped s) = showsPrec d s
+    show (Escaped s)        = show s
+
 linkSegments :: Link -> [String]
-linkSegments = _segments
+linkSegments = map getEscaped . _segments
 
 linkQueryParams :: Link -> [Param]
 linkQueryParams = _queryParams
@@ -149,7 +161,7 @@
     | FlagParam      String
   deriving Show
 
-addSegment :: String -> Link -> Link
+addSegment :: Escaped -> Link -> Link
 addSegment seg l = l { _segments = _segments l <> [seg] }
 
 addQueryParam :: Param -> Link -> Link
@@ -170,6 +182,14 @@
 -- >>> linkURI $ safeLink (Proxy :: Proxy API) (Proxy :: Proxy API)
 -- foo%2Fbar
 --
+-- >>> type SomeRoute = "abc" :> Capture "email" String :> Put '[JSON] ()
+-- >>> let someRoute = Proxy :: Proxy SomeRoute
+-- >>> safeLink someRoute someRoute "test@example.com"
+-- Link {_segments = ["abc","test%40example.com"], _queryParams = []}
+--
+-- >>> linkURI $ safeLink someRoute someRoute "test@example.com"
+-- abc/test%40example.com
+--
 linkURI :: Link -> URI
 linkURI = linkURI' LinkArrayElementBracket
 
@@ -192,7 +212,7 @@
 linkURI' addBrackets (Link segments q_params) =
     URI mempty  -- No scheme (relative)
         Nothing -- Or authority (relative)
-        (intercalate "/" $ map escape segments)
+        (intercalate "/" $ map getEscaped segments)
         (makeQueries q_params) mempty
   where
     makeQueries :: [Param] -> String
@@ -257,7 +277,7 @@
 instance (KnownSymbol sym, HasLink sub) => HasLink (sym :> sub) where
     type MkLink (sym :> sub) = MkLink sub
     toLink _ =
-        toLink (Proxy :: Proxy sub) . addSegment seg
+        toLink (Proxy :: Proxy sub) . addSegment (escaped seg)
       where
         seg = symbolVal (Proxy :: Proxy sym)
 
@@ -307,14 +327,14 @@
     type MkLink (Capture sym v :> sub) = v -> MkLink sub
     toLink _ l v =
         toLink (Proxy :: Proxy sub) $
-            addSegment (escape . Text.unpack $ toUrlPiece v) l
+            addSegment (escaped . Text.unpack $ toUrlPiece v) l
 
 instance (ToHttpApiData v, HasLink sub)
     => HasLink (CaptureAll sym v :> sub) where
     type MkLink (CaptureAll sym v :> sub) = [v] -> MkLink sub
     toLink _ l vs =
         toLink (Proxy :: Proxy sub) $
-            foldl' (flip $ addSegment . escape . Text.unpack . toUrlPiece) l vs
+            foldl' (flip $ addSegment . escaped . Text.unpack . toUrlPiece) l vs
 
 instance HasLink sub => HasLink (Header sym a :> sub) where
     type MkLink (Header sym a :> sub) = MkLink sub
