diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js
index 9b14ec6caac..1115f9515f7 100644
--- a/src/traces/sankey/plot.js
+++ b/src/traces/sankey/plot.js
@@ -178,13 +178,17 @@ module.exports = function plot(gd, calcData) {
         function hoverCenterPosition(link) {
             var hoverCenterX, hoverCenterY;
             if(link.circular) {
-                hoverCenterX = (link.circularPathData.leftInnerExtent + link.circularPathData.rightInnerExtent) / 2 + d.parent.translateX;
-                hoverCenterY = link.circularPathData.verticalFullExtent + d.parent.translateY;
+                hoverCenterX = (link.circularPathData.leftInnerExtent + link.circularPathData.rightInnerExtent) / 2;
+                hoverCenterY = link.circularPathData.verticalFullExtent;
             } else {
-                hoverCenterX = (link.source.x1 + link.target.x0) / 2 + d.parent.translateX;
-                hoverCenterY = (link.y0 + link.y1) / 2 + d.parent.translateY;
+                hoverCenterX = (link.source.x1 + link.target.x0) / 2;
+                hoverCenterY = (link.y0 + link.y1) / 2;
             }
-            return [hoverCenterX, hoverCenterY];
+            var center = [hoverCenterX, hoverCenterY];
+            if(link.trace.orientation === 'v') center.reverse();
+            center[0] += d.parent.translateX;
+            center[1] += d.parent.translateY;
+            return center;
         }
 
         // For each related links, create a hoverItem
diff --git a/test/jasmine/tests/sankey_test.js b/test/jasmine/tests/sankey_test.js
index e995d92eaa4..5f0f02e5c07 100644
--- a/test/jasmine/tests/sankey_test.js
+++ b/test/jasmine/tests/sankey_test.js
@@ -777,6 +777,42 @@ describe('sankey tests', function() {
             .then(done);
         });
 
+        it('should position hover labels correctly', function(done) {
+            var gd = createGraphDiv();
+            var mockCopy = Lib.extendDeep({}, mock);
+
+            Plotly.plot(gd, mockCopy)
+            .then(function() {
+                _hover(900, 230);
+
+                assertLabel(
+                    ['source: Thermal generation', 'target: Losses', '787TWh'],
+                    ['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)']
+                );
+
+                var g = d3.select('.hovertext');
+                var pos = g.node().getBoundingClientRect();
+                expect(pos.x).toBeCloseTo(555, -1.5, 'it should have correct x position');
+                expect(pos.y).toBeCloseTo(196, -1.5, 'it should have correct y position');
+                return Plotly.restyle(gd, 'orientation', 'v');
+            })
+            .then(function() {
+                _hover(520, 500);
+
+                assertLabel(
+                    ['source: Thermal generation', 'target: Losses', '787TWh'],
+                    ['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)']
+                );
+
+                var g = d3.select('.hovertext');
+                var pos = g.node().getBoundingClientRect();
+                expect(pos.x).toBeCloseTo(279, -1.5, 'it should have correct x position');
+                expect(pos.y).toBeCloseTo(500, -1.5, 'it should have correct y position');
+            })
+            .catch(failTest)
+            .then(done);
+        });
+
         it('should show the correct hover labels when hovertemplate is specified', function(done) {
             var gd = createGraphDiv();
             var mockCopy = Lib.extendDeep({}, mock);