Index: trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 15820)
@@ -18,5 +18,4 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiPredicate;
 
@@ -31,36 +30,4 @@
  */
 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);
-    }
 
     /**
@@ -284,5 +251,5 @@
     public void clearOsmMetadata() {
         // Not part of dataset - no lock necessary
-        this.id = generateUniqueId();
+        this.id = getIdGenerator().generateUniqueId();
         this.version = 0;
         this.user = null;
@@ -293,4 +260,11 @@
         this.setVisible(true);
     }
+
+    /**
+     * Returns the unique identifier generator.
+     * @return the unique identifier generator
+     * @since 15820
+     */
+    public abstract UniqueIdGenerator getIdGenerator();
 
     @Override
Index: trunk/src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 15820)
@@ -26,4 +26,6 @@
  */
 public final class Node extends OsmPrimitive implements INode {
+
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
 
     /*
@@ -423,3 +425,8 @@
         return false;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/NodeData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/NodeData.java	(revision 15820)
@@ -13,4 +13,5 @@
 
     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
@@ -24,4 +25,5 @@
     public NodeData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
@@ -109,3 +111,8 @@
         return false;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 15820)
@@ -112,5 +112,5 @@
                 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: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 15820)
@@ -16,14 +16,14 @@
 
     /** 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);
@@ -32,9 +32,12 @@
     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;
     }
 
@@ -154,4 +157,13 @@
     }
 
+    /**
+     * Returns the unique identifier generator.
+     * @return the unique identifier generator
+     * @since 15820
+     */
+    public final UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
+
     @Override
     public String toString() {
Index: trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java	(revision 15820)
@@ -26,11 +26,4 @@
 
     private static final long serialVersionUID = -1044837092478109138L;
-
-    /**
-     * Constructs a new {@code PrimitiveData}.
-     */
-    public PrimitiveData() {
-        this(OsmPrimitive.generateUniqueId());
-    }
 
     /**
Index: trunk/src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/Relation.java	(revision 15820)
@@ -28,4 +28,6 @@
  */
 public final class Relation extends OsmPrimitive implements IRelation<RelationMember> {
+
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
 
     private RelationMember[] members = new RelationMember[0];
@@ -550,3 +552,8 @@
                 .map(m -> (OsmPrimitive) m).collect(Collectors.toList());
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/RelationData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/RelationData.java	(revision 15820)
@@ -14,4 +14,5 @@
 
     private static final long serialVersionUID = 1163664954890478565L;
+    private static final UniqueIdGenerator idGenerator = Relation.idGenerator;
     private List<RelationMemberData> members = new ArrayList<>();
 
@@ -21,4 +22,5 @@
     public RelationData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
@@ -100,3 +102,8 @@
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java	(revision 15820)
+++ trunk/src/org/openstreetmap/josm/data/osm/UniqueIdGenerator.java	(revision 15820)
@@ -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 15820
+ */
+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);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 15820)
@@ -28,4 +28,6 @@
  */
 public final class Way extends OsmPrimitive implements IWay<Node> {
+
+    static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
 
     /**
@@ -749,3 +751,8 @@
         return angles;
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/WayData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/data/osm/WayData.java	(revision 15820)
@@ -14,4 +14,5 @@
 
     private static final long serialVersionUID = 106944939313286415L;
+    private static final UniqueIdGenerator idGenerator = Way.idGenerator;
     private List<Long> nodes = new ArrayList<>();
 
@@ -21,4 +22,5 @@
     public WayData() {
         // contents can be set later with setters
+        this(idGenerator.generateUniqueId());
     }
 
@@ -130,3 +132,8 @@
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public UniqueIdGenerator getIdGenerator() {
+        return idGenerator;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/AbstractReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 15818)
+++ trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 15820)
@@ -326,8 +326,12 @@
             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());
+                    }
                 }
             }
@@ -615,7 +619,7 @@
     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());
@@ -655,5 +659,5 @@
     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)) {
