Index: src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(working copy)
@@ -17,7 +17,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiPredicate;
 
 import org.openstreetmap.josm.data.gpx.GpxConstants;
@@ -31,38 +30,6 @@
  */
 public abstract class AbstractPrimitive implements IPrimitive {
 
-    private static final AtomicLong idCounter = new AtomicLong(0);
-
-    /**
-     * Generates a new primitive unique id.
-     * @return new primitive unique (negative) id
-     */
-    static long generateUniqueId() {
-        return idCounter.decrementAndGet();
-    }
-
-    /**
-     * Returns the current primitive unique id.
-     * @return the current primitive unique (negative) id (last generated)
-     * @since 12536
-     */
-    public static long currentUniqueId() {
-        return idCounter.get();
-    }
-
-    /**
-     * Advances the current primitive unique id to skip a range of values.
-     * @param newId new unique id
-     * @throws IllegalArgumentException if newId is greater than current unique id
-     * @since 12536
-     */
-    public static void advanceUniqueId(long newId) {
-        if (newId > currentUniqueId()) {
-            throw new IllegalArgumentException("Cannot modify the id counter backwards");
-        }
-        idCounter.set(newId);
-    }
-
     /**
      * This flag shows, that the properties have been changed by the user
      * and on upload the object will be send to the server.
@@ -283,7 +250,7 @@
      */
     public void clearOsmMetadata() {
         // Not part of dataset - no lock necessary
-        this.id = generateUniqueId();
+        this.id = getIdGenerator().generateUniqueId();
         this.version = 0;
         this.user = null;
         this.changesetId = 0; // reset changeset id on a new object
@@ -293,6 +260,13 @@
         this.setVisible(true);
     }
 
+    /**
+     * Returns the unique identifier generator.
+     * @return the unique identifier generator
+     * @since xxx
+     */
+    public abstract UniqueIdGenerator getIdGenerator();
+
     @Override
     public User getUser() {
         return user;
Index: src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Node.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/Node.java	(working copy)
@@ -26,6 +26,8 @@
  */
 public final class Node extends OsmPrimitive implements INode {
 
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
+
     /*
      * We "inline" lat/lon rather than using a LatLon-object => reduces memory footprint
      */
@@ -422,4 +424,9 @@
         }
         return false;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/osm/NodeData.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/NodeData.java	(working copy)
@@ -12,6 +12,7 @@
 public class NodeData extends PrimitiveData implements INode {
 
     private static final long serialVersionUID = 5626323599550908773L;
+    private static final UniqueIdGenerator idGenerator = Node.idGenerator;
     /*
      * we "inline" lat/lon coordinates instead of using a LatLon => reduces memory footprint
      */
@@ -23,6 +24,7 @@
      */
     public NodeData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
     /**
@@ -108,4 +110,9 @@
     public boolean isReferredByWays(int n) {
         return false;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(working copy)
@@ -111,7 +111,7 @@
             if (id < 0)
                 throw new IllegalArgumentException(MessageFormat.format("Expected ID >= 0. Got {0}.", id));
             else if (id == 0) {
-                this.id = generateUniqueId();
+                this.id = getIdGenerator().generateUniqueId();
             } else {
                 this.id = id;
             }
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(working copy)
@@ -15,27 +15,30 @@
 public enum OsmPrimitiveType {
 
     /** Node type */
-    NODE(marktr(/* ICON(data/) */"node"), Node.class, NodeData.class),
+    NODE(marktr(/* ICON(data/) */"node"), Node.class, NodeData.class, Node.idGenerator),
     /** Way type */
-    WAY(marktr(/* ICON(data/) */"way"), Way.class, WayData.class),
+    WAY(marktr(/* ICON(data/) */"way"), Way.class, WayData.class, Way.idGenerator),
     /** Relation type */
-    RELATION(marktr(/* ICON(data/) */"relation"), Relation.class, RelationData.class),
+    RELATION(marktr(/* ICON(data/) */"relation"), Relation.class, RelationData.class, Relation.idGenerator),
 
     /** Closed way: only for display, no real type */
-    CLOSEDWAY(marktr(/* ICON(data/) */"closedway"), null, WayData.class),
+    CLOSEDWAY(marktr(/* ICON(data/) */"closedway"), null, WayData.class, Way.idGenerator),
     /** Multipolygon: only for display, no real type */
-    MULTIPOLYGON(marktr(/* ICON(data/) */"multipolygon"), null, RelationData.class);
+    MULTIPOLYGON(marktr(/* ICON(data/) */"multipolygon"), null, RelationData.class, Relation.idGenerator);
 
     private static final Collection<OsmPrimitiveType> DATA_VALUES = Arrays.asList(NODE, WAY, RELATION);
 
     private final String apiTypeName;
     private final Class<? extends OsmPrimitive> osmClass;
     private final Class<? extends PrimitiveData> dataClass;
+    private final UniqueIdGenerator idGenerator;
 
-    OsmPrimitiveType(String apiTypeName, Class<? extends OsmPrimitive> osmClass, Class<? extends PrimitiveData> dataClass) {
+    OsmPrimitiveType(String apiTypeName, Class<? extends OsmPrimitive> osmClass, Class<? extends PrimitiveData> dataClass,
+            UniqueIdGenerator idGenerator) {
         this.apiTypeName = apiTypeName;
         this.osmClass = osmClass;
         this.dataClass = dataClass;
+        this.idGenerator = idGenerator;
     }
 
     /**
@@ -153,6 +156,15 @@
         }
     }
 
+    /**
+     * Returns the unique identifier generator.
+     * @return the unique identifier generator
+     * @since xxx
+     */
+    public final UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
+
     @Override
     public String toString() {
         return tr(getAPIName());
Index: src/org/openstreetmap/josm/data/osm/PrimitiveData.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(working copy)
@@ -27,13 +27,6 @@
     private static final long serialVersionUID = -1044837092478109138L;
 
     /**
-     * Constructs a new {@code PrimitiveData}.
-     */
-    public PrimitiveData() {
-        this(OsmPrimitive.generateUniqueId());
-    }
-
-    /**
      * Constructs a new {@code PrimitiveData} with given id.
      * @param id id
      * @since 12017
Index: src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Relation.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/Relation.java	(working copy)
@@ -28,6 +28,8 @@
  */
 public final class Relation extends OsmPrimitive implements IRelation<RelationMember> {
 
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
+
     private RelationMember[] members = new RelationMember[0];
 
     private BBox bbox;
@@ -549,4 +551,9 @@
                 .filter(m -> m instanceof OsmPrimitive)
                 .map(m -> (OsmPrimitive) m).collect(Collectors.toList());
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/osm/RelationData.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/RelationData.java	(working copy)
@@ -13,6 +13,7 @@
 public class RelationData extends PrimitiveData implements IRelation<RelationMemberData> {
 
     private static final long serialVersionUID = 1163664954890478565L;
+    private static final UniqueIdGenerator idGenerator = Relation.idGenerator;
     private List<RelationMemberData> members = new ArrayList<>();
 
     /**
@@ -20,6 +21,7 @@
      */
     public RelationData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
     /**
@@ -99,4 +101,9 @@
     public BBox getBBox() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java	(nonexistent)
+++ src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java	(working copy)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Generator of unique identifiers.
+ * @since xxx
+ */
+public final class UniqueIdGenerator {
+
+    private final AtomicLong idCounter = new AtomicLong(0);
+
+    /**
+     * Generates a new primitive unique id.
+     * @return new primitive unique (negative) id
+     */
+    long generateUniqueId() {
+        return idCounter.decrementAndGet();
+    }
+
+    /**
+     * Returns the current primitive unique id.
+     * @return the current primitive unique (negative) id (last generated)
+     */
+    public long currentUniqueId() {
+        return idCounter.get();
+    }
+
+    /**
+     * Advances the current primitive unique id to skip a range of values.
+     * @param newId new unique id
+     * @throws IllegalArgumentException if newId is greater than current unique id
+     */
+    public void advanceUniqueId(long newId) {
+        if (newId > currentUniqueId()) {
+            throw new IllegalArgumentException("Cannot modify the id counter backwards");
+        }
+        idCounter.set(newId);
+    }
+}

Property changes on: src\org\openstreetmap\josm\data\osm\UniqueIdGenerator.java
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Way.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/Way.java	(working copy)
@@ -28,6 +28,8 @@
  */
 public final class Way extends OsmPrimitive implements IWay<Node> {
 
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
+
     /**
      * All way nodes in this way
      */
@@ -748,4 +750,9 @@
 
         return angles;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/data/osm/WayData.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/WayData.java	(revision 15801)
+++ src/org/openstreetmap/josm/data/osm/WayData.java	(working copy)
@@ -13,6 +13,7 @@
 public class WayData extends PrimitiveData implements IWay<NodeData> {
 
     private static final long serialVersionUID = 106944939313286415L;
+    private static final UniqueIdGenerator idGenerator = Way.idGenerator;
     private List<Long> nodes = new ArrayList<>();
 
     /**
@@ -20,6 +21,7 @@
      */
     public WayData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
     /**
@@ -129,4 +131,9 @@
     public boolean isInnerNode(INode n) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: src/org/openstreetmap/josm/io/AbstractReader.java
===================================================================
--- src/org/openstreetmap/josm/io/AbstractReader.java	(revision 15801)
+++ src/org/openstreetmap/josm/io/AbstractReader.java	(working copy)
@@ -325,10 +325,14 @@
         } catch (IOException e) {
             throw new IllegalDataException(e);
         } finally {
-            OptionalLong minId = externalIdMap.values().stream().mapToLong(AbstractPrimitive::getUniqueId).min();
-            synchronized (AbstractPrimitive.class) {
-                if (minId.isPresent() && minId.getAsLong() < AbstractPrimitive.currentUniqueId()) {
-                    AbstractPrimitive.advanceUniqueId(minId.getAsLong());
+            for (OsmPrimitiveType dataType : OsmPrimitiveType.dataValues()) {
+                OptionalLong minId = externalIdMap.entrySet().parallelStream()
+                        .filter(e -> e.getKey().getType() == dataType)
+                        .mapToLong(e -> e.getValue().getUniqueId()).min();
+                synchronized (dataType.getDataClass()) {
+                    if (minId.isPresent() && minId.getAsLong() < dataType.getIdGenerator().currentUniqueId()) {
+                        dataType.getIdGenerator().advanceUniqueId(minId.getAsLong());
+                    }
                 }
             }
             progressMonitor.finishTask();
@@ -614,9 +618,9 @@
 
     protected OsmPrimitive buildPrimitive(PrimitiveData pd) {
         OsmPrimitive p;
-        if (pd.getUniqueId() < AbstractPrimitive.currentUniqueId()) {
+        if (pd.getUniqueId() < pd.getIdGenerator().currentUniqueId()) {
             p = pd.getType().newInstance(pd.getUniqueId(), true);
-            AbstractPrimitive.advanceUniqueId(pd.getUniqueId());
+            pd.getIdGenerator().advanceUniqueId(pd.getUniqueId());
         } else {
             p = pd.getType().newVersionedInstance(pd.getId(), pd.getVersion());
         }
@@ -654,7 +658,7 @@
 
     protected final Node parseNode(String lat, String lon, CommonReader commonReader, NodeReader nodeReader)
             throws IllegalDataException {
-        NodeData nd = new NodeData();
+        NodeData nd = new NodeData(0);
         LatLon ll = null;
         if (areLatLonDefined(lat, lon)) {
             try {
