diff --git a/src/org/openstreetmap/josm/tools/ImageProvider.java b/src/org/openstreetmap/josm/tools/ImageProvider.java
index c07e0c88a..138ed46f9 100644
--- a/src/org/openstreetmap/josm/tools/ImageProvider.java
+++ b/src/org/openstreetmap/josm/tools/ImageProvider.java
@@ -1328,6 +1328,10 @@ public class ImageProvider {
         return Toolkit.getDefaultToolkit().createCustomCursor(image, hotSpot, name);
     }
 
+    static final int CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO = 32;  // the following cursor hotspot constants are relative to this cursor size
+    private static final Point DEFAULT_HOTSPOT = new Point(3, 2);  // FIXME: define better hotspot for rotate.png
+    private static final Point CROSSHAIR_HOTSPOT = new Point(10, 10);
+
     /**
      * Load a cursor image with a given file name, optionally decorated with an overlay image
      *
@@ -1344,7 +1348,7 @@ public class ImageProvider {
                 .addOverlay(new ImageOverlay(new ImageProvider("cursor/modifier/" + overlay)
                                                 .setMaxSize(ImageSizes.CURSOROVERLAY)));
         }
-        hotSpot.setLocation("crosshair".equals(name) ? new Point(10, 10) : new Point(3, 2));
+        hotSpot.setLocation("crosshair".equals(name) ? CROSSHAIR_HOTSPOT : DEFAULT_HOTSPOT);
         ImageIcon imageIcon = imageProvider.get();
         Image image = imageIcon.getImage();
         int width = image.getWidth(null);
@@ -1360,11 +1364,11 @@ public class ImageProvider {
             if (bestCursorSize.width != image.getWidth(null) || bestCursorSize.height != image.getHeight(null)) {
                 image = image.getScaledInstance(bestCursorSize.width, bestCursorSize.height, Image.SCALE_DEFAULT);
             }
-
-            hotSpot.x = hotSpot.x * bestCursorSize.width / width;
-            hotSpot.y = hotSpot.y * bestCursorSize.height / height;
         }
 
+        hotSpot.x = hotSpot.x * image.getWidth(null) / CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
+        hotSpot.y = hotSpot.y * image.getHeight(null) / CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
+
         return image;
     }
 
diff --git a/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java b/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java
index bdf0ae0e8..6e53122bd 100644
--- a/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java
@@ -193,8 +193,6 @@ public class ImageProviderTest {
         }
     }
 
-    public static final int ORIGINAL_CURSOR_SIZE = 32;
-
     /**
      * Test getting an image for a crosshair cursor.
      */
@@ -214,10 +212,16 @@ public class ImageProviderTest {
      */
     @Test
     public void testGetCursorImageWithOverlay() {
+        testCursorImageWithOverlay(1.0f);  // normal case
+        testCursorImageWithOverlay(1.5f);  // user has configured a GUI scale of 1.5 in the JOSM advanced preferences
+    }
+
+    private void testCursorImageWithOverlay(float guiScale) {
         if (GraphicsEnvironment.isHeadless()) {
             // TODO mock Toolkit.getDefaultToolkit().getBestCursorSize()
             return;
         }
+        GuiSizesHelper.setPixelDensity(guiScale);
         Point hotSpot = new Point();
         Image image = ImageProvider.getCursorImage("normal", "selection", hotSpot);
         assertCursorDimensionsCorrect(new Point.Double(3.0, 2.0), image, hotSpot);
@@ -236,14 +240,15 @@ public class ImageProviderTest {
     }
 
     private void assertCursorDimensionsCorrect(Point.Double originalHotspot, Image image, Point hotSpot) {
-        Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(ORIGINAL_CURSOR_SIZE, ORIGINAL_CURSOR_SIZE);
+        int originalCursorSize = ImageProvider.CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
+        Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(originalCursorSize, originalCursorSize);
         Image bestCursorImage = HiDPISupport.getResolutionVariant(image, bestCursorSize.width, bestCursorSize.height);
         int bestCursorImageWidth = bestCursorImage.getWidth(null);
         assertEquals((int) Math.round(bestCursorSize.getWidth()), bestCursorImageWidth);
         int bestCursorImageHeight = bestCursorImage.getHeight(null);
         assertEquals((int) Math.round(bestCursorSize.getHeight()), bestCursorImageHeight);
-        assertEquals(originalHotspot.x / ORIGINAL_CURSOR_SIZE * bestCursorImageWidth, hotSpot.x, 1 /* at worst one pixel off */);
-        assertEquals(originalHotspot.y / ORIGINAL_CURSOR_SIZE * bestCursorImageHeight, hotSpot.y, 1 /* at worst one pixel off */);
+        assertEquals(originalHotspot.x / originalCursorSize * bestCursorImageWidth, hotSpot.x, 1 /* at worst one pixel off */);
+        assertEquals(originalHotspot.y / originalCursorSize * bestCursorImageHeight, hotSpot.y, 1 /* at worst one pixel off */);
     }
 
 
