Merge branch 'geoapi-4.0' into geoapi-3.1
diff --git a/application/pom.xml b/application/pom.xml
index d3d1d3f..0db0ec5 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-console/pom.xml b/application/sis-console/pom.xml
index 050ab66..6bec4bb 100644
--- a/application/sis-console/pom.xml
+++ b/application/sis-console/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>application</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-console/src/main/artifact/bin/sis b/application/sis-console/src/main/artifact/bin/sis
index b0fd28f..d0560d9 100755
--- a/application/sis-console/src/main/artifact/bin/sis
+++ b/application/sis-console/src/main/artifact/bin/sis
@@ -24,7 +24,7 @@
 export SIS_DATA
 
 # Execute SIS with any optional JAR that the user may put in the 'lib' directory.
-java -classpath "$BASE_DIR/lib/sis-console-2.0-SNAPSHOT.jar" \
+java -classpath "$BASE_DIR/lib/sis-console-1.x-SNAPSHOT.jar" \
      -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \
      -Dderby.stream.error.file="$BASE_DIR/log/derby.log" \
      org.apache.sis.console.Command $SIS_OPTS "$@"
diff --git a/application/sis-javafx/pom.xml b/application/sis-javafx/pom.xml
index c5219fd..80a0a50 100644
--- a/application/sis-javafx/pom.xml
+++ b/application/sis-javafx/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>application</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-javafx/src/main/artifact/bin/sisfx b/application/sis-javafx/src/main/artifact/bin/sisfx
index 1439fff..90b93e9 100755
--- a/application/sis-javafx/src/main/artifact/bin/sisfx
+++ b/application/sis-javafx/src/main/artifact/bin/sisfx
@@ -38,7 +38,7 @@
 java -splash:"$BASE_DIR/lib/logo.jpg" \
      --add-modules javafx.graphics,javafx.controls,javafx.web \
      --module-path "$PATH_TO_FX" \
-     --class-path "$BASE_DIR/lib/sis-javafx-2.0-SNAPSHOT.jar" \
+     --class-path "$BASE_DIR/lib/sis-javafx-1.x-SNAPSHOT.jar" \
      -Djava.util.logging.config.class="org.apache.sis.internal.setup.LoggingConfiguration" \
      -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \
      -Dderby.stream.error.file="$BASE_DIR/log/derby.log" \
diff --git a/application/sis-javafx/src/main/artifact/bin/sisfx.bat b/application/sis-javafx/src/main/artifact/bin/sisfx.bat
index 04affb2..aa85eba 100644
--- a/application/sis-javafx/src/main/artifact/bin/sisfx.bat
+++ b/application/sis-javafx/src/main/artifact/bin/sisfx.bat
@@ -29,7 +29,7 @@
 java -splash:"%BASE_DIR%\lib\logo.jpg"^
  --add-modules javafx.graphics,javafx.controls,javafx.web^
  --module-path "%PATH_TO_FX%"^
- --class-path "%BASE_DIR%\lib\sis-javafx-2.0-SNAPSHOT.jar"^
+ --class-path "%BASE_DIR%\lib\sis-javafx-1.x-SNAPSHOT.jar"^
  -Djava.util.logging.config.class=org.apache.sis.internal.setup.LoggingConfiguration^
  -Djava.util.logging.config.file="%BASE_DIR%\conf\logging.properties"^
  -Dderby.stream.error.file="%BASE_DIR%\log\derby.log"^
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/IdentificationInfo.java b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/IdentificationInfo.java
index 8da5616..0ad5de9 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/IdentificationInfo.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/gui/metadata/IdentificationInfo.java
@@ -41,7 +41,6 @@
 import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.metadata.identification.Identification;
 import org.opengis.metadata.distribution.Format;
-import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.referencing.IdentifiedObjects;
@@ -299,8 +298,8 @@
             label = Vocabulary.Keys.Purpose;
             text = owner.string(info.getPurpose());
             if (text == null) {
-                for (final InternationalString c : nonNull(info.getCredits())) {
-                    text = owner.string(c);
+                for (final String c : nonNull(info.getCredits())) {
+                    text = c;
                     if (text != null) {
                         label = Vocabulary.Keys.Credit;
                         break;
diff --git a/application/sis-openoffice/pom.xml b/application/sis-openoffice/pom.xml
index 30ac919..5f82836 100644
--- a/application/sis-openoffice/pom.xml
+++ b/application/sis-openoffice/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>application</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-webapp/pom.xml b/application/sis-webapp/pom.xml
index 1a8ab81..762493c 100644
--- a/application/sis-webapp/pom.xml
+++ b/application/sis-webapp/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>application</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.application</groupId>
diff --git a/cloud/pom.xml b/cloud/pom.xml
index 3a2959c..d91b8b4 100644
--- a/cloud/pom.xml
+++ b/cloud/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/cloud/sis-cloud-aws/pom.xml b/cloud/sis-cloud-aws/pom.xml
index 21af1ab..3be2ec6 100644
--- a/cloud/sis-cloud-aws/pom.xml
+++ b/cloud/sis-cloud-aws/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>cloud</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/pom.xml b/core/pom.xml
index 6b9f8f3..cfda747 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-build-helper/pom.xml b/core/sis-build-helper/pom.xml
index 23132ca..3030641 100644
--- a/core/sis-build-helper/pom.xml
+++ b/core/sis-build-helper/pom.xml
@@ -32,7 +32,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
diff --git a/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst b/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
index fa371b7..1959531 100644
--- a/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
+++ b/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
@@ -123,6 +123,7 @@
 MathTransform2D
 Medium
 MediumFormat
+MediumName
 Metadata
 MetadataExtensionInformation
 MetadataScope
diff --git a/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst b/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
index 771ccac..9aec1eb 100644
--- a/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
+++ b/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
@@ -151,6 +151,7 @@
 MD_MaintenanceInformation
 MD_Medium
 MD_MediumFormatCode
+MD_MediumNameCode
 MD_Metadata
 MD_MetadataExtensionInformation
 MD_MetadataScope
diff --git a/core/sis-cql/pom.xml b/core/sis-cql/pom.xml
index 6674905..40c207a 100644
--- a/core/sis-cql/pom.xml
+++ b/core/sis-cql/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-feature/pom.xml b/core/sis-feature/pom.xml
index 301e441..05f39c7 100644
--- a/core/sis-feature/pom.xml
+++ b/core/sis-feature/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java b/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
index d47b929..20697e8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
@@ -28,7 +28,7 @@
 import org.apache.sis.metadata.iso.quality.DefaultDataQuality;
 import org.apache.sis.metadata.iso.quality.DefaultDomainConsistency;
 import org.apache.sis.metadata.iso.quality.DefaultConformanceResult;
-import org.apache.sis.metadata.iso.maintenance.DefaultScope;
+import org.apache.sis.metadata.iso.quality.DefaultScope;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.util.resources.Errors;
 
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java b/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java
index cee59c2..0a9dd86 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java
@@ -18,7 +18,6 @@
 
 import java.util.Date;
 import java.io.Serializable;
-import org.opengis.metadata.Identifier;
 import org.apache.sis.test.TestUtilities;
 
 // Branch-dependent imports
@@ -31,6 +30,7 @@
 import org.opengis.temporal.TemporalPosition;
 import org.opengis.temporal.TemporalPrimitive;
 import org.opengis.temporal.TemporalGeometricPrimitive;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -65,7 +65,7 @@
             @Override public String toString() {return "Instant[" + TestUtilities.format(getDate()) + '[';}
 
             /** Not needed for the tests. */
-            @Override public Identifier       getName()                              {throw new UnsupportedOperationException();}
+            @Override public ReferenceIdentifier getName()                           {throw new UnsupportedOperationException();}
             @Override public TemporalPosition getTemporalPosition()                  {throw new UnsupportedOperationException();}
             @Override public RelativePosition relativePosition(TemporalPrimitive o)  {throw new UnsupportedOperationException();}
             @Override public Duration         distance(TemporalGeometricPrimitive o) {throw new UnsupportedOperationException();}
@@ -74,7 +74,7 @@
     }
 
     /** Not needed for the tests. */
-    @Override public Identifier       getName()                              {throw new UnsupportedOperationException();}
+    @Override public ReferenceIdentifier getName()                           {throw new UnsupportedOperationException();}
     @Override public RelativePosition relativePosition(TemporalPrimitive o)  {throw new UnsupportedOperationException();}
     @Override public Duration         distance(TemporalGeometricPrimitive o) {throw new UnsupportedOperationException();}
     @Override public Duration         length()                               {throw new UnsupportedOperationException();}
diff --git a/core/sis-metadata/pom.xml b/core/sis-metadata/pom.xml
index 2721092..e37fcbf 100644
--- a/core/sis-metadata/pom.xml
+++ b/core/sis-metadata/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
index 901c73b..ae81bbf 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
@@ -127,7 +127,33 @@
      */
     @Override
     public final ValueType marshal(final BoundType code) {
-        return (code != null) ? wrap(new CodeListUID(Context.current(), code)) : null;
+        if (code == null) {
+            return null;
+        }
+        final CodeListUID p;
+        if (isEnum()) {
+            // To be removed after GEO-199 resolution.
+            p = new CodeListUID();
+            p.value = Types.getCodeName(code);
+        } else {
+            p = new CodeListUID(Context.current(), code);
+        }
+        return wrap(p);
+    }
+
+    /**
+     * Returns {@code true} if this code list is actually an enum. The default implementation
+     * returns {@code false} in every cases, since there is very few enums in ISO 19115.
+     *
+     * @return {@code true} if this code list is actually an enum.
+     *
+     * @todo Remove this method after we refactored enum wrappers as {@code EnumAdapter} subclasses
+     *       instead of {@code CodeListAdapter}. This requires the resolution of GEO-199 first.
+     *
+     * @see <a href="http://jira.codehaus.org/browse/GEO-199">GEO-199</a>
+     */
+    protected boolean isEnum() {
+        return false;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_MediumNameCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_MediumNameCode.java
index b2f18be..fbf9d24 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_MediumNameCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_MediumNameCode.java
@@ -17,10 +17,10 @@
 package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
+import org.opengis.metadata.distribution.MediumName;
 import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
 import org.apache.sis.internal.jaxb.cat.CodeListUID;
 import org.apache.sis.internal.xml.LegacyNamespaces;
-import org.apache.sis.internal.metadata.legacy.MediumName;
 
 
 /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
index 4b88e53..31c876e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
@@ -18,7 +18,8 @@
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.spatial.PixelOrientation;
-import org.apache.sis.internal.jaxb.cat.EnumAdapter;
+import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
+import org.apache.sis.internal.jaxb.cat.CodeListUID;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -33,13 +34,9 @@
  * @since   0.3
  * @module
  */
-public final class MD_PixelOrientationCode extends EnumAdapter<MD_PixelOrientationCode, PixelOrientation> {
-    /**
-     * The enumeration value.
-     */
-    @XmlElement(name = "MD_PixelOrientationCode", namespace = Namespaces.MSR)
-    private String value;
-
+public final class MD_PixelOrientationCode
+        extends CodeListAdapter<MD_PixelOrientationCode, PixelOrientation>
+{
     /**
      * Empty constructor for JAXB only.
      */
@@ -47,29 +44,57 @@
     }
 
     /**
-     * Returns the wrapped value.
-     *
-     * @param  wrapper  the wrapper.
-     * @return the wrapped value.
+     * Creates a new adapter for the given proxy.
      */
-    @Override
-    public final PixelOrientation unmarshal(final MD_PixelOrientationCode wrapper) {
-        return PixelOrientation.valueOf(name(wrapper.value));
+    private MD_PixelOrientationCode(final CodeListUID value) {
+        super(value);
     }
 
     /**
-     * Wraps the given value.
+     * {@inheritDoc}
      *
-     * @param  e  the value to wrap.
-     * @return the wrapped value.
+     * @return the wrapper for the code list value.
      */
     @Override
-    public final MD_PixelOrientationCode marshal(final PixelOrientation e) {
-        if (e == null) {
-            return null;
-        }
-        final MD_PixelOrientationCode wrapper = new MD_PixelOrientationCode();
-        wrapper.value = value(e);
-        return wrapper;
+    protected MD_PixelOrientationCode wrap(final CodeListUID value) {
+        return new MD_PixelOrientationCode(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the code list class.
+     */
+    @Override
+    protected Class<PixelOrientation> getCodeListClass() {
+        return PixelOrientation.class;
+    }
+
+    /**
+     * Returns {@code true} since this code list is actually an enum.
+     */
+    @Override
+    protected boolean isEnum() {
+        return true;
+    }
+
+    /**
+     * Invoked by JAXB on marshalling.
+     *
+     * @return The value to be marshalled.
+     */
+    @Override
+    @XmlElement(name = "MD_PixelOrientationCode", namespace = Namespaces.MSR)
+    public CodeListUID getElement() {
+        return identifier;
+    }
+
+    /**
+     * Invoked by JAXB on unmarshalling.
+     *
+     * @param value The unmarshalled value.
+     */
+    public void setElement(final CodeListUID value) {
+        identifier = value;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
index dae9784..7d700ca 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
@@ -18,7 +18,8 @@
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.identification.TopicCategory;
-import org.apache.sis.internal.jaxb.cat.EnumAdapter;
+import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
+import org.apache.sis.internal.jaxb.cat.CodeListUID;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -34,13 +35,7 @@
  * @since   0.3
  * @module
  */
-public final class MD_TopicCategoryCode extends EnumAdapter<MD_TopicCategoryCode, TopicCategory> {
-    /**
-     * The enumeration value.
-     */
-    @XmlElement(name = "MD_TopicCategoryCode", namespace = Namespaces.MRI)
-    private String value;
-
+public final class MD_TopicCategoryCode extends CodeListAdapter<MD_TopicCategoryCode, TopicCategory> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -48,29 +43,57 @@
     }
 
     /**
-     * Returns the wrapped value.
-     *
-     * @param  wrapper  the wrapper.
-     * @return the wrapped value.
+     * Creates a new adapter for the given proxy.
      */
-    @Override
-    public final TopicCategory unmarshal(final MD_TopicCategoryCode wrapper) {
-        return TopicCategory.valueOf(name(wrapper.value));
+    private MD_TopicCategoryCode(final CodeListUID value) {
+        super(value);
     }
 
     /**
-     * Wraps the given value.
+     * {@inheritDoc}
      *
-     * @param  e  the value to wrap.
-     * @return the wrapped value.
+     * @return the wrapper for the code list value.
      */
     @Override
-    public final MD_TopicCategoryCode marshal(final TopicCategory e) {
-        if (e == null) {
-            return null;
-        }
-        final MD_TopicCategoryCode wrapper = new MD_TopicCategoryCode();
-        wrapper.value = value(e);
-        return wrapper;
+    protected MD_TopicCategoryCode wrap(final CodeListUID value) {
+        return new MD_TopicCategoryCode(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the code list class.
+     */
+    @Override
+    protected Class<TopicCategory> getCodeListClass() {
+        return TopicCategory.class;
+    }
+
+    /**
+     * Returns {@code true} since this code list is actually an enum.
+     */
+    @Override
+    protected boolean isEnum() {
+        return true;
+    }
+
+    /**
+     * Invoked by JAXB on marshalling.
+     *
+     * @return The value to be marshalled.
+     */
+    @Override
+    @XmlElement(name = "MD_TopicCategoryCode", namespace = Namespaces.MRI)
+    public CodeListUID getElement() {
+        return identifier;
+    }
+
+    /**
+     * Invoked by JAXB on unmarshalling.
+     *
+     * @param value The unmarshalled value.
+     */
+    public void setElement(final CodeListUID value) {
+        identifier = value;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MI_PolarisationOrientationCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MI_PolarisationOrientationCode.java
index 8a2f8a0..d704bea 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MI_PolarisationOrientationCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MI_PolarisationOrientationCode.java
@@ -17,14 +17,14 @@
 package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.metadata.content.PolarisationOrientation;
+import org.opengis.metadata.content.PolarizationOrientation;
 import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
 import org.apache.sis.internal.jaxb.cat.CodeListUID;
 import org.apache.sis.xml.Namespaces;
 
 
 /**
- * JAXB adapter for {@link PolarisationOrientation}
+ * JAXB adapter for {@link PolarizationOrientation}
  * in order to wrap the value in an XML element as specified by ISO 19115-3 standard.
  * See package documentation for more information about the handling of {@code CodeList} in ISO 19115-3.
  *
@@ -38,7 +38,7 @@
  * @module
  */
 public final class MI_PolarisationOrientationCode
-        extends CodeListAdapter<MI_PolarisationOrientationCode, PolarisationOrientation>
+        extends CodeListAdapter<MI_PolarisationOrientationCode, PolarizationOrientation>
 {
     /**
      * Empty constructor for JAXB only.
@@ -69,8 +69,8 @@
      * @return the code list class.
      */
     @Override
-    protected Class<PolarisationOrientation> getCodeListClass() {
-        return PolarisationOrientation.class;
+    protected Class<PolarizationOrientation> getCodeListClass() {
+        return PolarizationOrientation.class;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/PropertyType.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/PropertyType.java
index 62d945e..78a013d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/PropertyType.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/PropertyType.java
@@ -583,7 +583,8 @@
      * @throws URISyntaxException if a URI can not be parsed.
      */
     @Override
-    public final BoundType unmarshal(final ValueType value) throws URISyntaxException {
+    // Overridden by `MD_Scope` on the geoapi-3.x branches only.
+    public BoundType unmarshal(final ValueType value) throws URISyntaxException {
         return (value != null) ? value.resolve(Context.current()) : null;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gmi/MI_Band.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gmi/MI_Band.java
index c105e55..83bfdba 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gmi/MI_Band.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gmi/MI_Band.java
@@ -69,8 +69,8 @@
             if (original.getBandBoundaryDefinition()   != null ||
                 original.getNominalSpatialResolution() != null ||
                 original.getTransferFunctionType()     != null ||
-                original.getTransmittedPolarisation()  != null ||
-                original.getDetectedPolarisation()     != null)
+                original.getTransmittedPolarization()  != null ||
+                original.getDetectedPolarization()     != null)
             {
                 return new MI_Band(original);
             }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java
index 0b04680..7fa2fdc 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java
@@ -33,17 +33,13 @@
  * JAXB adapter mapping implementing class to a legacy GeoAPI interface.
  * See package documentation for more information about JAXB and interface.
  *
- * @deprecated This adapter is not used anymore for ISO 19115-3:2014 metadata.
- * However it is needed for branches that depend on GeoAPI 3.x, and is also needed
- * for implementing web services that have not yet been upgraded to latest ISO standard.
- *
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   0.3
  * @module
  */
-@Deprecated
+@SuppressWarnings("deprecation")
 public final class CI_ResponsibleParty extends PropertyType<CI_ResponsibleParty, ResponsibleParty> {
     /**
      * Empty constructor for JAXB only.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Scope.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Scope.java
index 3dbcbd5..65f78ea 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Scope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Scope.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.jaxb.metadata;
 
+import java.net.URISyntaxException;
 import javax.xml.bind.annotation.XmlElementRef;
 import org.opengis.metadata.maintenance.Scope;
 import org.apache.sis.metadata.iso.maintenance.DefaultScope;
@@ -92,6 +93,21 @@
     }
 
     /**
+     * On unmarshalling, creates an instance of the deprecated
+     * {@link org.apache.sis.metadata.iso.quality.DefaultScope} subclass.
+     */
+    public static final class Legacy extends MD_Scope {
+        /** Empty constructor used only by JAXB. */
+        public Legacy() {
+        }
+
+        /** Converts an adapter read from an XML stream. */
+        @Override public Scope unmarshal(final MD_Scope value) throws URISyntaxException {
+            return org.apache.sis.metadata.iso.quality.DefaultScope.castOrCopy(super.unmarshal(value));
+        }
+    }
+
+    /**
      * Wraps the value only if marshalling an element from the ISO 19115:2003 metadata model.
      * Otherwise (i.e. if marshalling according legacy ISO 19115:2014 model), omits the element.
      */
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/RS_Identifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/RS_Identifier.java
index 240a6b5..bf9bc48 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/RS_Identifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/RS_Identifier.java
@@ -20,6 +20,8 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.Identifier;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.metadata.TitleProperty;
 import org.apache.sis.internal.xml.LegacyNamespaces;
 
@@ -51,7 +53,7 @@
 @TitleProperty(name = "code")
 @XmlType(name = "RS_Identifier_Type", namespace = LegacyNamespaces.GMD)
 @XmlRootElement(name = "RS_Identifier", namespace = LegacyNamespaces.GMD)
-public final class RS_Identifier extends DefaultIdentifier {
+public final class RS_Identifier extends DefaultIdentifier implements ReferenceIdentifier {
     /**
      * For cross-version compatibility.
      */
@@ -64,6 +66,27 @@
     }
 
     /**
+     * Creates a new identifier initialized to the given code, code space and version number.
+     *
+     * @param codeSpace  identifier or namespace in which the code is valid, or {@code null} if not available.
+     * @param code       alphanumeric value identifying an instance in the namespace, or {@code null} if none.
+     * @param version    the version identifier for the namespace as specified by the code authority, or {@code null} if none.
+     */
+    public RS_Identifier(final String codeSpace, final String code, final String version) {
+        super(codeSpace, code, version);
+    }
+
+    /**
+     * Creates an identifier initialized to the given authority and code.
+     *
+     * @param authority  the the person or party responsible for maintenance of the namespace, or {@code null} if none.
+     * @param code       the alphanumeric value identifying an instance in the namespace, or {@code null} if none.
+     */
+    public RS_Identifier(final Citation authority, final String code) {
+        super(authority, code);
+    }
+
+    /**
      * Creates a new identifier from the specified one.
      *
      * @see #wrap(Identifier)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
index 5e27cb9..6c4703e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
@@ -20,8 +20,8 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.SimpleIdentifiedObject;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.util.ComparisonMode;
@@ -93,7 +93,7 @@
      *
      * @param  name  the primary name by which this object is identified.
      */
-    public ReferenceSystemMetadata(final Identifier name) {
+    public ReferenceSystemMetadata(final ReferenceIdentifier name) {
         super(name);
     }
 
@@ -112,8 +112,8 @@
      */
     @Override
     @XmlElement(name = "referenceSystemIdentifier")
-    public final Identifier getName() {
-        Identifier name = super.getName();
+    public final ReferenceIdentifier getName() {
+        ReferenceIdentifier name = super.getName();
         if (isLegacyMetadata) {
             name = RS_Identifier.wrap(name);
         }
@@ -125,7 +125,7 @@
      *
      * @param  name  the new primary name.
      */
-    public final void setName(final Identifier name) {
+    public final void setName(final ReferenceIdentifier name) {
         this.name = name;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
index f318736..8b190ed 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
@@ -29,6 +29,7 @@
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.SimpleIdentifiedObject;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.xml.LegacyNamespaces;
@@ -264,10 +265,10 @@
      * @return the parameter name as an identifier (the type specified by ISO 19111).
      */
     @Override
-    public synchronized Identifier getName() {
+    public synchronized ReferenceIdentifier getName() {
         if (name == null && memberName != null) {
-            if (memberName instanceof Identifier) {
-                name = (Identifier) memberName;
+            if (memberName instanceof ReferenceIdentifier) {
+                name = (ReferenceIdentifier) memberName;
             } else {
                 name = new NameToIdentifier(memberName);
             }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
index f52559e..b8112d7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
@@ -25,6 +25,7 @@
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.CharSequences;
@@ -46,7 +47,7 @@
  * @since   0.4
  * @module
  */
-public final class NameToIdentifier implements Identifier {
+public final class NameToIdentifier implements ReferenceIdentifier {
     /**
      * The name from which to infer the identifier attributes.
      */
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/legacy/MediumName.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/legacy/MediumName.java
deleted file mode 100644
index 937059e..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/legacy/MediumName.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.internal.metadata.legacy;
-
-import java.util.List;
-import java.util.ArrayList;
-import org.opengis.annotation.UML;
-import org.opengis.metadata.citation.Citation;
-import org.opengis.util.CodeList;
-import org.opengis.util.InternationalString;
-import org.apache.sis.internal.util.CodeLists;
-import org.apache.sis.util.iso.Types;
-
-import static org.opengis.annotation.Obligation.*;
-import static org.opengis.annotation.Specification.*;
-
-
-/**
- * Name of the medium as defined in legacy ISO 19115:2003.
- * In more recent specification, this code list has been replaced by a citation.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 2.0
- *
- * @see <a href="https://issues.apache.org/jira/browse/SIS-389">SIS-389</a>
- * @see <a href="https://github.com/opengeospatial/geoapi/issues/14">GeoAPI issue #14</a>
- *
- * @since 2.0
- * @module
- */
-@UML(identifier="MD_MediumNameCode", specification=ISO_19115, version=2003)
-public final class MediumName extends CodeList<MediumName> implements Citation {
-    /** Serial number for compatibility with different versions. */
-    private static final long serialVersionUID = 7157038832444373933L;
-
-    /** List of all enumerations of this type. */
-    private static final List<MediumName> VALUES = new ArrayList<>(18);
-
-    /** Read-only optical disk. */
-    @UML(identifier="cdRom", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CD_ROM = new MediumName("CD_ROM");
-
-    /** Digital versatile disk. */
-    @UML(identifier="dvd", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName DVD = new MediumName("DVD");
-
-    /** Digital versatile disk digital versatile disk, read only. */
-    @UML(identifier="dvdRom", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName DVD_ROM = new MediumName("DVD_ROM");
-
-    /** 3½ inch magnetic disk. */
-    @UML(identifier="3halfInchFloppy", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName FLOPPY_3_HALF_INCH = new MediumName("FLOPPY_3_HALF_INCH");
-
-    /** 5¼ inch magnetic disk. */
-    @UML(identifier="5quarterInchFloppy", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName FLOPPY_5_QUARTER_INCH = new MediumName("FLOPPY_5_QUARTER_INCH");
-
-    /** 7 track magnetic tape. */
-    @UML(identifier="7trackTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName TAPE_7_TRACK = new MediumName("TAPE_7_TRACK");
-
-    /** 9 track magnetic tape. */
-    @UML(identifier="9trackTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName TAPE_9_TRACK = new MediumName("TAPE_9_TRACK");
-
-    /** 3480 cartridge tape drive. */
-    @UML(identifier="3480Cartridge", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3480 = new MediumName("CARTRIDGE_3480");
-
-    /** 3490 cartridge tape drive. */
-    @UML(identifier="3490Cartridge", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3490 = new MediumName("CARTRIDGE_3490");
-
-    /** 3580 cartridge tape drive. */
-    @UML(identifier="3580Cartridge", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3580 = new MediumName("CARTRIDGE_3580");
-
-    /** 4 millimetre magnetic tape. */
-    @UML(identifier="4mmCartridgeTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_4mm = new MediumName("CARTRIDGE_TAPE_4mm");
-
-    /** 8 millimetre magnetic tape. */
-    @UML(identifier="8mmCartridgeTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_8mm = new MediumName("CARTRIDGE_TAPE_8mm");
-
-    /** ¼ inch magnetic tape. */
-    @UML(identifier="1quarterInchCartridgeTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_1_QUARTER_INCH = new MediumName("CARTRIDGE_TAPE_1_QUARTER_INCH");
-
-    /** Half inch cartridge streaming tape drive. */
-    @UML(identifier="digitalLinearTape", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName DIGITAL_LINEAR_TAPE = new MediumName("DIGITAL_LINEAR_TAPE");
-
-    /** Direct computer linkage. */
-    @UML(identifier="onLine", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName ON_LINE = new MediumName("ON_LINE");
-
-    /** Linkage through a satellite communication system. */
-    @UML(identifier="satellite", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName SATELLITE = new MediumName("SATELLITE");
-
-    /** Communication through a telephone network. */
-    @UML(identifier="telephoneLink", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName TELEPHONE_LINK = new MediumName("TELEPHONE_LINK");
-
-    /** Pamphlet or leaflet giving descriptive information. */
-    @UML(identifier="hardcopy", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName HARDCOPY = new MediumName("HARDCOPY");
-
-    /** Constructs an element of the given name. */
-    private MediumName(final String name) {
-        super(name, VALUES);
-    }
-
-    /**
-     * Returns the list of {@code MediumName}s.
-     *
-     * @return the list of codes declared in the current JVM.
-     */
-    public static MediumName[] values() {
-        synchronized (VALUES) {
-            return VALUES.toArray(new MediumName[VALUES.size()]);
-        }
-    }
-
-    /**
-     * Returns the list of codes of the same kind than this code list element.
-     *
-     * @return all code {@linkplain #values() values} for this code list.
-     */
-    @Override
-    public MediumName[] family() {
-        return values();
-    }
-
-    /**
-     * Returns the medium name that matches the given string, or {@code null} if none match it.
-     * Contrarily to non-deprecated code list, this method does not create a new code if none match the given name.
-     *
-     * @param  code  the name of the code to fetch or to create.
-     * @return a code matching the given name, or {@code null}.
-     */
-    public static MediumName valueOf(final String code) {
-        return CodeLists.forName(MediumName.class, code, false);
-    }
-
-    /**
-     * Returns the given citation as a medium name code, or {@code null} if none.
-     *
-     * @param  citation  the medium name to return as a citation, or {@code null}.
-     * @return the code as a citation, or {@code null}.
-     */
-    public static MediumName castOrWrap(final Citation citation) {
-        if (citation instanceof MediumName) {
-            return (MediumName) citation;
-        }
-        if (citation != null) {
-            final InternationalString title = citation.getTitle();
-            if (title != null) {
-                return valueOf(title.toString());
-            }
-        }
-        return null;
-    }
-
-    /**
-     * {@link Citation} methods provided for transition from legacy code list to new citation type.
-     */
-    @Override
-    public InternationalString getTitle() {
-        return Types.toInternationalString(name());
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
index 34095c9..a2de591 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
@@ -24,7 +24,7 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.util.InternationalString;
@@ -204,10 +204,10 @@
     @Override public InternationalString                        getEdition()                 {return delegate().getEdition();}
     @Override public Date                                       getEditionDate()             {return delegate().getEditionDate();}
     @Override public Collection<? extends Identifier>           getIdentifiers()             {return delegate().getIdentifiers();}
-    @Override public Collection<? extends Responsibility>       getCitedResponsibleParties() {return delegate().getCitedResponsibleParties();}
+    @Override public Collection<? extends ResponsibleParty>     getCitedResponsibleParties() {return delegate().getCitedResponsibleParties();}
     @Override public Collection<PresentationForm>               getPresentationForms()       {return delegate().getPresentationForms();}
     @Override public Series                                     getSeries()                  {return delegate().getSeries();}
-    @Override public Collection<? extends InternationalString>  getOtherCitationDetails()    {return delegate().getOtherCitationDetails();}
+    @Override public InternationalString                        getOtherCitationDetails()    {return delegate().getOtherCitationDetails();}
     @Override public Collection<? extends OnlineResource>       getOnlineResources()         {return delegate().getOnlineResources();}
     @Override public Collection<? extends BrowseGraphic>        getGraphics()                {return delegate().getGraphics();}
     @Override public String                                     getISBN()                    {return delegate().getISBN();}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
index 9cc14d0..c2efe00 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
@@ -23,6 +23,7 @@
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.metadata.Identifiers;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.LenientComparable;
@@ -52,7 +53,7 @@
     /**
      * The primary name by which this object is identified.
      */
-    protected Identifier name;
+    protected ReferenceIdentifier name;
 
     /**
      * Creates an identified object without identifier.
@@ -75,7 +76,7 @@
      *
      * @param  name  the primary name by which this object is identified.
      */
-    public SimpleIdentifiedObject(final Identifier name) {
+    public SimpleIdentifiedObject(final ReferenceIdentifier name) {
         this.name = name;
     }
 
@@ -85,7 +86,7 @@
      * @return the identifier given at construction time.
      */
     @Override
-    public Identifier getName() {
+    public ReferenceIdentifier getName() {
         return name;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
index 1117bab..ae65239 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
@@ -19,7 +19,7 @@
 import java.util.Objects;
 import java.io.Serializable;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.CharSequences;
@@ -28,14 +28,14 @@
 
 
 /**
- * An implementation of {@link Identifier} as a wrapper around a {@link Citation}.
+ * An implementation of {@link ReferenceIdentifier} as a wrapper around a {@link Citation}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   0.3
  * @module
  */
-public class SimpleIdentifier implements Identifier, Deprecable, Serializable {
+public class SimpleIdentifier implements ReferenceIdentifier, Deprecable, Serializable {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
index d9b6811..523cb51 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
@@ -26,7 +26,7 @@
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.identification.*;
 import org.opengis.metadata.maintenance.ScopeCode;
@@ -108,7 +108,7 @@
      * Parties responsible for the metadata information.
      */
     @Override
-    public Collection<Responsibility> getContacts() {
+    public Collection<ResponsibleParty> getContacts() {
         return Collections.emptyList();
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
index a0ebf71..b0faf00 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
@@ -21,11 +21,11 @@
 import java.util.Collections;
 import java.lang.reflect.Method;
 import org.opengis.annotation.UML;
-import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
+import org.opengis.metadata.Obligation;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.ExtendedElementInformation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.util.CodeList;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.simple.SimpleIdentifier;
@@ -307,7 +307,7 @@
      * Returns the name of the person or organization creating the element.
      */
     @Override
-    public Collection<? extends Responsibility> getSources() {
+    public Collection<? extends ResponsibleParty> getSources() {
         return authority.getCitedResponsibleParties();
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
index 2621e3b..c7c7c64 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata.iso;
 
+import java.net.URI;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -24,8 +25,6 @@
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.OnlineResource;
 import org.apache.sis.xml.Namespaces;
-import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
-import org.apache.sis.internal.jaxb.metadata.CI_OnlineResource;
 
 
 /**
@@ -70,7 +69,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 5667352094985433121L;
+    private static final long serialVersionUID = -884081423040392985L;
 
     /**
      * Name of the application schema used.
@@ -90,17 +89,17 @@
     /**
      * Full application schema given as an ASCII file.
      */
-    private CharSequence schemaAscii;
+    private URI schemaAscii;
 
     /**
      * Full application schema given as a graphics file.
      */
-    private OnlineResource graphicsFile;
+    private URI graphicsFile;
 
     /**
      * Full application schema given as a software development file.
      */
-    private OnlineResource softwareDevelopmentFile;
+    private URI softwareDevelopmentFile;
 
     /**
      * Software dependent format used for the application schema software dependent file.
@@ -242,21 +241,29 @@
     /**
      * Full application schema given as an ASCII file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * {@code URI} may be replaced by {@link CharSequence} in GeoAPI 4.0.
+     * </div>
+     *
      * @return application schema as an ASCII file, or {@code null}.
      */
     @Override
     @XmlElement(name = "schemaAscii")
-    @XmlJavaTypeAdapter(CharSequenceAdapter.Since2014.class)
-    public CharSequence getSchemaAscii()  {
+    @XmlJavaTypeAdapter(URIStringAdapter.class)
+    public URI getSchemaAscii()  {
         return schemaAscii;
     }
 
     /**
      * Sets the full application schema given as an ASCII file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * {@code URI} may be replaced by {@link CharSequence} in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new ASCII file.
      */
-    public void setSchemaAscii(final CharSequence newValue) {
+    public void setSchemaAscii(final URI newValue) {
         checkWritePermission(schemaAscii);
         schemaAscii = newValue;
     }
@@ -264,21 +271,31 @@
     /**
      * Full application schema given as a graphics file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return application schema as a graphics file, or {@code null}.
      */
     @Override
     @XmlElement(name = "graphicsFile")
-    @XmlJavaTypeAdapter(CI_OnlineResource.Since2014.class)
-    public OnlineResource getGraphicsFile()  {
+    @XmlJavaTypeAdapter(OnlineResourceAdapter.class)
+    public URI getGraphicsFile()  {
         return graphicsFile;
     }
 
     /**
      * Sets the full application schema given as a graphics file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new graphics file.
      */
-    public void setGraphicsFile(final OnlineResource newValue) {
+    public void setGraphicsFile(final URI newValue) {
         checkWritePermission(graphicsFile);
         graphicsFile = newValue;
     }
@@ -286,21 +303,31 @@
     /**
      * Full application schema given as a software development file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return application schema as a software development file, or {@code null}.
      */
     @Override
     @XmlElement(name = "softwareDevelopmentFile")
-    @XmlJavaTypeAdapter(CI_OnlineResource.Since2014.class)
-    public OnlineResource getSoftwareDevelopmentFile()  {
+    @XmlJavaTypeAdapter(OnlineResourceAdapter.class)
+    public URI getSoftwareDevelopmentFile()  {
         return softwareDevelopmentFile;
     }
 
     /**
      * Sets the full application schema given as a software development file.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new software development file.
      */
-    public void setSoftwareDevelopmentFile(final OnlineResource newValue) {
+    public void setSoftwareDevelopmentFile(final URI newValue) {
         checkWritePermission(softwareDevelopmentFile);
         softwareDevelopmentFile = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
index 33417a1..2177eef 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
@@ -22,9 +22,9 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.Obligation;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.ExtendedElementInformation;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.TitleProperty;
@@ -101,7 +101,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 489138542195499530L;
+    private static final long serialVersionUID = 5892811836634834434L;
 
     /**
      * Name of the extended metadata element.
@@ -176,12 +176,12 @@
     /**
      * Reason for creating the extended element.
      */
-    private InternationalString rationale;
+    private Collection<InternationalString> rationales;
 
     /**
      * Name of the person or organization creating the extended element.
      */
-    private Collection<Responsibility> sources;
+    private Collection<ResponsibleParty> sources;
 
     /**
      * Construct an initially empty extended element information.
@@ -206,7 +206,7 @@
                                              final Datatype     dataType,
                                              final String       parentEntity,
                                              final CharSequence rule,
-                                             final Responsibility source)
+                                             final ResponsibleParty source)
     {
         this.name         = name;
         this.definition   = Types.toInternationalString(definition);
@@ -214,7 +214,7 @@
         this.dataType     = dataType;
         this.parentEntity = singleton(parentEntity, String.class);
         this.rule         = Types.toInternationalString(rule);
-        this.sources      = singleton(source, Responsibility.class);
+        this.sources      = singleton(source, ResponsibleParty.class);
     }
 
     /**
@@ -248,8 +248,8 @@
             domainValue       = object.getDomainValue();
             parentEntity      = copyCollection(object.getParentEntity(), String.class);
             rule              = object.getRule();
-            rationale         = object.getRationale();
-            sources           = copyCollection(object.getSources(), Responsibility.class);
+            rationales        = copyCollection(object.getRationales(), InternationalString.class);
+            sources           = copyCollection(object.getSources(), ResponsibleParty.class);
         }
     }
 
@@ -546,7 +546,8 @@
     @Override
     @XmlElement(name = "rationale")
     public InternationalString getRationale() {
-        return rationale;
+        return LegacyPropertyAdapter.getSingleton(rationales, InternationalString.class, null,
+                DefaultExtendedElementInformation.class, "getRationale");
     }
 
     /**
@@ -557,8 +558,7 @@
      * @since 0.5
      */
     public void setRationale(final InternationalString newValue) {
-        checkWritePermission(rationale);
-        rationale = newValue;
+        rationales = writeCollection(CollectionsExt.singletonOrEmpty(newValue), rationales, InternationalString.class);
     }
 
     /**
@@ -609,21 +609,31 @@
     /**
      * Name of the person or organization creating the extended element.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return name of the person or organization creating the extended element.
      */
     @Override
     @XmlElement(name = "source", required = true)
-    public Collection<Responsibility> getSources() {
-        return sources = nonNullCollection(sources, Responsibility.class);
+    public Collection<ResponsibleParty> getSources() {
+        return sources = nonNullCollection(sources, ResponsibleParty.class);
     }
 
     /**
      * Sets the name of the person or organization creating the extended element.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new sources.
      */
-    public void setSources(final Collection<? extends Responsibility> newValues) {
-        sources = writeCollection(newValues, sources, Responsibility.class);
+    public void setSources(final Collection<? extends ResponsibleParty> newValues) {
+        sources = writeCollection(newValues, sources, ResponsibleParty.class);
     }
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
index 158a871..3a21772 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
@@ -45,7 +45,7 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.content.ContentInformation;
 import org.opengis.metadata.distribution.Distribution;
@@ -202,7 +202,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -1128741312274891545L;
+    private static final long serialVersionUID = -76483485174667242L;
 
     /**
      * Language(s) and character set(s) used within the dataset.
@@ -222,7 +222,7 @@
     /**
      * Parties responsible for the metadata information.
      */
-    private Collection<Responsibility> contacts;
+    private Collection<ResponsibleParty> contacts;
 
     /**
      * Date(s) associated with the metadata.
@@ -278,7 +278,7 @@
     /**
      * Provides information about the distributor of and options for obtaining the resource(s).
      */
-    private Collection<Distribution> distributionInfo;
+    private Distribution distributionInfo;
 
     /**
      * Provides overall assessment of quality of a resource(s).
@@ -328,11 +328,11 @@
      * @param dateStamp           date that the metadata was created.
      * @param identificationInfo  basic information about the resource to which the metadata applies.
      */
-    public DefaultMetadata(final Responsibility contact,
+    public DefaultMetadata(final ResponsibleParty contact,
                            final Date           dateStamp,
                            final Identification identificationInfo)
     {
-        this.contacts  = singleton(contact, Responsibility.class);
+        this.contacts  = singleton(contact, ResponsibleParty.class);
         this.identificationInfo = singleton(identificationInfo, Identification.class);
         if (dateStamp != null) {
             dateInfo = singleton(new DefaultCitationDate(dateStamp, DateType.CREATION), CitationDate.class);
@@ -355,7 +355,7 @@
             parentMetadata                = object.getParentMetadata();
             locales                       = copyMap       (object.getLocalesAndCharsets(),            Locale.class);
             metadataScopes                = copyCollection(object.getMetadataScopes(),                MetadataScope.class);
-            contacts                      = copyCollection(object.getContacts(),                      Responsibility.class);
+            contacts                      = copyCollection(object.getContacts(),                      ResponsibleParty.class);
             dateInfo                      = copyCollection(object.getDateInfo(),                      CitationDate.class);
             metadataStandards             = copyCollection(object.getMetadataStandards(),             Citation.class);
             metadataProfiles              = copyCollection(object.getMetadataProfiles(),              Citation.class);
@@ -366,7 +366,7 @@
             metadataExtensionInfo         = copyCollection(object.getMetadataExtensionInfo(),         MetadataExtensionInformation.class);
             identificationInfo            = copyCollection(object.getIdentificationInfo(),            Identification.class);
             contentInfo                   = copyCollection(object.getContentInfo(),                   ContentInformation.class);
-            distributionInfo              = copyCollection(object.getDistributionInfo(),              Distribution.class);
+            distributionInfo              = object.getDistributionInfo();
             dataQualityInfo               = copyCollection(object.getDataQualityInfo(),               DataQuality.class);
             portrayalCatalogueInfo        = copyCollection(object.getPortrayalCatalogueInfo(),        PortrayalCatalogueReference.class);
             metadataConstraints           = copyCollection(object.getMetadataConstraints(),           Constraints.class);
@@ -936,12 +936,17 @@
     /**
      * Returns the parties responsible for the metadata information.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return parties responsible for the metadata information.
      */
     @Override
     @XmlElement(name = "contact", required = true)
-    public Collection<Responsibility> getContacts() {
-        return contacts = nonNullCollection(contacts, Responsibility.class);
+    public Collection<ResponsibleParty> getContacts() {
+        return contacts = nonNullCollection(contacts, ResponsibleParty.class);
     }
 
     /**
@@ -949,8 +954,8 @@
      *
      * @param  newValues  the new contacts.
      */
-    public void setContacts(final Collection<? extends Responsibility> newValues) {
-        contacts = writeCollection(newValues, contacts, Responsibility.class);
+    public void setContacts(final Collection<? extends ResponsibleParty> newValues) {
+        contacts = writeCollection(newValues, contacts, ResponsibleParty.class);
     }
 
     /**
@@ -1436,21 +1441,32 @@
     /**
      * Returns information about the distributor of and options for obtaining the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change will tentatively be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return the distributor of and options for obtaining the resource(s).
      */
     @Override
     @XmlElement(name = "distributionInfo")
-    public Collection<Distribution> getDistributionInfo() {
-        return distributionInfo = nonNullCollection(distributionInfo, Distribution.class);
+    public Distribution getDistributionInfo() {
+        return distributionInfo;
     }
 
     /**
      * Sets information about the distributor of and options for obtaining the resource(s).
      *
-     * @param  newValues  the new distribution info.
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change will tentatively be applied in GeoAPI 4.0.
+     * </div>
+     *
+     * @param  newValue  the new distribution info.
      */
-    public void setDistributionInfo(final Collection<? extends Distribution> newValues) {
-        distributionInfo = writeCollection(newValues, distributionInfo, Distribution.class);
+    public void setDistributionInfo(final Distribution newValue) {
+        checkWritePermission(distributionInfo);
+        distributionInfo = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java
new file mode 100644
index 0000000..9e7a202
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.iso;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.metadata.citation.OnlineResource;
+import org.apache.sis.internal.jaxb.metadata.CI_OnlineResource;
+import org.apache.sis.metadata.iso.citation.DefaultOnlineResource;
+
+
+/**
+ * Converts an URI to a {@code <cit:OnlineResource>} element for ISO 19115-3:2016 compliance.
+ * We need this additional adapter because some property type changed from {@code URI} to
+ * {@code OnlineResource} in the upgrade from ISO 19115:2003 to ISO 19115-1:2014.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ */
+final class OnlineResourceAdapter extends XmlAdapter<CI_OnlineResource, URI> {
+    /**
+     * The adapter performing the actual work.
+     */
+    private static final CI_OnlineResource ADAPTER = new CI_OnlineResource.Since2014();
+
+    /**
+     * Wraps the given URI in a {@code <cit:OnlineResource>} element.
+     */
+    @Override
+    public CI_OnlineResource marshal(final URI value) {
+        if (value != null) {
+            return ADAPTER.marshal(new DefaultOnlineResource(value));
+        }
+        return null;
+    }
+
+    /**
+     * Returns a URI from the given {@code <cit:OnlineResource>} element.
+     */
+    @Override
+    public URI unmarshal(final CI_OnlineResource value) throws URISyntaxException {
+        if (value != null) {
+            final OnlineResource res = ADAPTER.unmarshal(value);
+            if (res != null) {
+                return res.getLinkage();
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java
new file mode 100644
index 0000000..07b42c5
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.iso;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
+import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
+
+
+/**
+ * Converts an URI to a {@code <gco:CharacterSequence>} element for ISO 19115-3:2016 compliance.
+ * We need this additional adapter because some property type changed from {@code URI}
+ * to {@code CharacterSequence} in the upgrade from ISO 19115:2003 to ISO 19115-1:2014.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ */
+final class URIStringAdapter extends XmlAdapter<GO_CharacterString, URI> {
+    /**
+     * The adapter performing the actual work.
+     */
+    private static final CharSequenceAdapter ADAPTER = new CharSequenceAdapter.Since2014();
+
+    /**
+     * Wraps the given URI in a {@code <cit:OnlineResource>} element.
+     */
+    @Override
+    public GO_CharacterString marshal(final URI value) {
+        if (value != null) {
+            return ADAPTER.marshal(value.toString());
+        }
+        return null;
+    }
+
+    /**
+     * Returns a URI from the given {@code <cit:OnlineResource>} element.
+     */
+    @Override
+    public URI unmarshal(final GO_CharacterString value) throws URISyntaxException {
+        if (value != null) {
+            final CharSequence uri = ADAPTER.unmarshal(value);
+            if (uri != null) {
+                final Context context = Context.current();
+                return Context.converter(context).toURI(context, uri.toString());
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
index c867a72..c0e4fd4 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
@@ -139,7 +139,7 @@
             types                = copyCollection(object.getTypes(), ObjectiveType.class);
             functions            = copyCollection(object.getFunctions(), InternationalString.class);
             extents              = copyCollection(object.getExtents(), Extent.class);
-            objectiveOccurrences = copyCollection(object.getObjectiveOccurrences(), Event.class);
+            objectiveOccurrences = copyCollection(object.getObjectiveOccurences(), Event.class);
             pass                 = copyCollection(object.getPass(), PlatformPass.class);
             sensingInstruments   = copyCollection(object.getSensingInstruments(), Instrument.class);
         }
@@ -290,23 +290,47 @@
      * Returns the event or events associated with objective completion.
      *
      * @return events associated with objective completion.
+     *
+     * @since 1.0
      */
-    @Override
     @XmlElement(name = "objectiveOccurence", required = true)
     public Collection<Event> getObjectiveOccurrences() {
         return objectiveOccurrences = nonNullCollection(objectiveOccurrences, Event.class);
     }
 
     /**
+     * @deprecated Renamed {@link #getObjectiveOccurrences()}.
+     *
+     * @return events associated with objective completion.
+     */
+    @Override
+    @Deprecated
+    public Collection<Event> getObjectiveOccurences() {
+        return getObjectiveOccurrences();
+    }
+
+    /**
      * Sets the event or events associated with objective completion.
      *
      * @param  newValues  the new objective occurrences values.
+     *
+     * @since 1.0
      */
     public void setObjectiveOccurrences(final Collection<? extends Event> newValues) {
         objectiveOccurrences = writeCollection(newValues, objectiveOccurrences, Event.class);
     }
 
     /**
+     * @deprecated Renamed {@link #setObjectiveOccurrences(Collection)}.
+     *
+     * @param  newValues  the new objective occurrences values.
+     */
+    @Deprecated
+    public void setObjectiveOccurences(final Collection<? extends Event> newValues) {
+        setObjectiveOccurrences(newValues);
+    }
+
+    /**
      * Returns the pass of the platform over the objective.
      *
      * @return pass of the platform.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
index 4d75155..1871a67 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
@@ -24,7 +24,7 @@
 import org.opengis.metadata.acquisition.Instrument;
 import org.opengis.metadata.acquisition.Platform;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
@@ -83,7 +83,7 @@
     /**
      * Organization responsible for building, launch, or operation of the platform.
      */
-    private Collection<Responsibility> sponsors;
+    private Collection<ResponsibleParty> sponsors;
 
     /**
      * Instrument(s) mounted on a platform.
@@ -111,7 +111,7 @@
             citation    = object.getCitation();
             identifiers = singleton(object.getIdentifier(), Identifier.class);
             description = object.getDescription();
-            sponsors    = copyCollection(object.getSponsors(), Responsibility.class);
+            sponsors    = copyCollection(object.getSponsors(), ResponsibleParty.class);
             instruments = copyCollection(object.getInstruments(), Instrument.class);
         }
     }
@@ -207,21 +207,31 @@
     /**
      * Returns the organization responsible for building, launch, or operation of the platform.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return organization responsible for building, launch, or operation of the platform.
      */
     @Override
     @XmlElement(name = "sponsor")
-    public Collection<Responsibility> getSponsors() {
-        return sponsors = nonNullCollection(sponsors, Responsibility.class);
+    public Collection<ResponsibleParty> getSponsors() {
+        return sponsors = nonNullCollection(sponsors, ResponsibleParty.class);
     }
 
     /**
      * Sets the organization responsible for building, launch, or operation of the platform.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new sponsors values;
      */
-    public void setSponsors(final Collection<? extends Responsibility> newValues) {
-        sponsors = writeCollection(newValues, sponsors, Responsibility.class);
+    public void setSponsors(final Collection<? extends ResponsibleParty> newValues) {
+        sponsors = writeCollection(newValues, sponsors, ResponsibleParty.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
index 0624a19..32d4add 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
@@ -27,7 +27,7 @@
 import org.opengis.metadata.acquisition.RequestedDate;
 import org.opengis.metadata.acquisition.Requirement;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
@@ -93,12 +93,12 @@
     /**
      * Origin of requirement.
      */
-    private Collection<Responsibility> requestors;
+    private Collection<ResponsibleParty> requestors;
 
     /**
      * Person(s), or body(ies), to receive results of requirement.
      */
-    private Collection<Responsibility> recipients;
+    private Collection<ResponsibleParty> recipients;
 
     /**
      * Relative ordered importance, or urgency, of the requirement.
@@ -141,8 +141,8 @@
         if (object != null) {
             citation       = object.getCitation();
             identifiers    = singleton(object.getIdentifier(), Identifier.class);
-            requestors     = copyCollection(object.getRequestors(), Responsibility.class);
-            recipients     = copyCollection(object.getRecipients(), Responsibility.class);
+            requestors     = copyCollection(object.getRequestors(), ResponsibleParty.class);
+            recipients     = copyCollection(object.getRecipients(), ResponsibleParty.class);
             priority       = object.getPriority();
             requestedDate  = object.getRequestedDate();
             expiryDate     = toMilliseconds(object.getExpiryDate());
@@ -221,41 +221,61 @@
     /**
      * Returns the origin of requirement.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return origin of requirement.
      */
     @Override
     @XmlElement(name = "requestor", required = true)
-    public Collection<Responsibility> getRequestors() {
-        return requestors = nonNullCollection(requestors, Responsibility.class);
+    public Collection<ResponsibleParty> getRequestors() {
+        return requestors = nonNullCollection(requestors, ResponsibleParty.class);
     }
 
     /**
      * Sets the origin of requirement.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new requestors values.
      */
-    public void setRequestors(final Collection<? extends Responsibility> newValues) {
-        requestors = writeCollection(newValues, requestors, Responsibility.class);
+    public void setRequestors(final Collection<? extends ResponsibleParty> newValues) {
+        requestors = writeCollection(newValues, requestors, ResponsibleParty.class);
     }
 
     /**
      * Returns the person(s), or body(ies), to receive results of requirement.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return person(s), or body(ies), to receive results.
      */
     @Override
     @XmlElement(name = "recipient", required = true)
-    public Collection<Responsibility> getRecipients() {
-        return recipients = nonNullCollection(recipients, Responsibility.class);
+    public Collection<ResponsibleParty> getRecipients() {
+        return recipients = nonNullCollection(recipients, ResponsibleParty.class);
     }
 
     /**
      * Sets the Person(s), or body(ies), to receive results of requirement.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new recipients values.
      */
-    public void setRecipients(final Collection<? extends Responsibility> newValues) {
-        recipients = writeCollection(newValues, recipients, Responsibility.class);
+    public void setRecipients(final Collection<? extends ResponsibleParty> newValues) {
+        recipients = writeCollection(newValues, recipients, ResponsibleParty.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
index 1db697b..45b74b9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
@@ -100,7 +100,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(GO_Real.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
index 6310f6c..bc2211b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
@@ -82,7 +82,7 @@
     /**
      * Address line for the location (as described in ISO 11180, Annex A).
      */
-    private Collection<InternationalString> deliveryPoints;
+    private Collection<String> deliveryPoints;
 
     /**
      * Address of the electronic mailbox of the responsible organization or individual.
@@ -107,7 +107,7 @@
     public DefaultAddress(final Address object) {
         super(object);
         if (object != null) {
-            deliveryPoints          = copyCollection(object.getDeliveryPoints(), InternationalString.class);
+            deliveryPoints          = copyCollection(object.getDeliveryPoints(), String.class);
             city                    = object.getCity();
             administrativeArea      = object.getAdministrativeArea();
             postalCode              = object.getPostalCode();
@@ -207,21 +207,31 @@
     /**
      * Returns the address line for the location (as described in ISO 11180, Annex A).
      *
+     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
+     * The return type may be changed from {@code Collection<String>} to
+     * {@code Collection<? extends InternationalString>} in GeoAPI 4.0.
+     * </div>
+     *
      * @return address line for the location.
      */
     @Override
     @XmlElement(name = "deliveryPoint")
-    public Collection<InternationalString> getDeliveryPoints() {
-        return deliveryPoints = nonNullCollection(deliveryPoints, InternationalString.class);
+    public Collection<String> getDeliveryPoints() {
+        return deliveryPoints = nonNullCollection(deliveryPoints, String.class);
     }
 
     /**
      * Sets the address line for the location (as described in ISO 11180, Annex A).
      *
+     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
+     * The argument type may be changed from {@code Collection<String>} to
+     * {@code Collection<? extends InternationalString>} in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new delivery points, or {@code null} if none.
      */
-    public void setDeliveryPoints(final Collection<? extends InternationalString> newValues) {
-        deliveryPoints = writeCollection(newValues, deliveryPoints, InternationalString.class);
+    public void setDeliveryPoints(final Collection<? extends String> newValues) {
+        deliveryPoints = writeCollection(newValues, deliveryPoints, String.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
index 6e2ff87..f0795df 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
@@ -26,7 +26,7 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.util.InternationalString;
@@ -98,7 +98,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -7343644724857519090L;
+    private static final long serialVersionUID = 3490090845236158848L;
 
     /**
      * Name by which the cited resource is known.
@@ -131,7 +131,7 @@
      * Roles, Name, contact, and position information for an individual or organization that is responsible
      * for the resource.
      */
-    private Collection<Responsibility> citedResponsibleParties;
+    private Collection<ResponsibleParty> citedResponsibleParties;
 
     /**
      * Mode in which the resource is represented, or an empty collection if none.
@@ -148,7 +148,7 @@
      * Other information required to complete the citation that is not recorded elsewhere.
      * May be {@code null} if none.
      */
-    private Collection<InternationalString> otherCitationDetails;
+    private InternationalString otherCitationDetails;
 
     /**
      * Common title with holdings note. Note: title identifies elements of a series
@@ -205,10 +205,10 @@
             edition                 = object.getEdition();
             editionDate             = toMilliseconds(object.getEditionDate());
             identifiers             = copyCollection(object.getIdentifiers(), Identifier.class);
-            citedResponsibleParties = copyCollection(object.getCitedResponsibleParties(), Responsibility.class);
+            citedResponsibleParties = copyCollection(object.getCitedResponsibleParties(), ResponsibleParty.class);
             presentationForms       = copyCollection(object.getPresentationForms(), PresentationForm.class);
             series                  = object.getSeries();
-            otherCitationDetails    = copyCollection(object.getOtherCitationDetails(), InternationalString.class);
+            otherCitationDetails    = object.getOtherCitationDetails();
             collectiveTitle         = object.getCollectiveTitle();
             onlineResources         = copyCollection(object.getOnlineResources(), OnlineResource.class);
             graphics                = copyCollection(object.getGraphics(), BrowseGraphic.class);
@@ -401,22 +401,32 @@
      * Returns the role, name, contact and position information for an individual or organization
      * that is responsible for the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return the individual or organization that is responsible, or an empty collection if none.
      */
     @Override
     @XmlElement(name = "citedResponsibleParty")
-    public Collection<Responsibility> getCitedResponsibleParties() {
-        return citedResponsibleParties = nonNullCollection(citedResponsibleParties, Responsibility.class);
+    public Collection<ResponsibleParty> getCitedResponsibleParties() {
+        return citedResponsibleParties = nonNullCollection(citedResponsibleParties, ResponsibleParty.class);
     }
 
     /**
      * Sets the role, name, contact and position information for an individual or organization
      * that is responsible for the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new cited responsible parties, or {@code null} if none.
      */
-    public void setCitedResponsibleParties(final Collection<? extends Responsibility> newValues) {
-        citedResponsibleParties = writeCollection(newValues, citedResponsibleParties, Responsibility.class);
+    public void setCitedResponsibleParties(final Collection<? extends ResponsibleParty> newValues) {
+        citedResponsibleParties = writeCollection(newValues, citedResponsibleParties, ResponsibleParty.class);
     }
 
     /**
@@ -463,21 +473,32 @@
     /**
      * Returns other information required to complete the citation that is not recorded elsewhere.
      *
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return other details, or {@code null} if none.
      */
     @Override
     @XmlElement(name = "otherCitationDetails")
-    public Collection<InternationalString> getOtherCitationDetails() {
-        return otherCitationDetails = nonNullCollection(otherCitationDetails, InternationalString.class);
+    public InternationalString getOtherCitationDetails() {
+        return otherCitationDetails;
     }
 
     /**
      * Sets other information required to complete the citation that is not recorded elsewhere.
      *
-     * @param newValues Other citations details.
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
+     * @param newValue Other citations details, or {@code null} if none.
      */
-    public void setOtherCitationDetails(final Collection<? extends InternationalString> newValues) {
-        otherCitationDetails = writeCollection(newValues, otherCitationDetails, InternationalString.class);
+    public void setOtherCitationDetails(final InternationalString newValue) {
+        checkWritePermission(otherCitationDetails);
+        otherCitationDetails = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
index ea9dd8b..eafc326 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
@@ -97,7 +97,7 @@
     /**
      * Time period (including time zone) when individuals can contact the organization or individual.
      */
-    private Collection<InternationalString> hoursOfService;
+    private InternationalString hoursOfService;
 
     /**
      * Supplemental instructions on how or when to contact the individual or organization.
@@ -140,7 +140,7 @@
             phones              = copyCollection(object.getPhones(), Telephone.class);
             addresses           = copyCollection(object.getAddresses(), Address.class);
             onlineResources     = copyCollection(object.getOnlineResources(), OnlineResource.class);
-            hoursOfService      = copyCollection(object.getHoursOfService(), InternationalString.class);
+            hoursOfService      = object.getHoursOfService();
             contactInstructions = object.getContactInstructions();
             contactType         = object.getContactType();
         }
@@ -400,21 +400,32 @@
     /**
      * Returns the time period (including time zone) when individuals can contact the organization or individual.
      *
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change will tentatively be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return time period when individuals can contact the organization or individual.
      */
     @Override
     @XmlElement(name = "hoursOfService")
-    public Collection<InternationalString> getHoursOfService() {
-        return hoursOfService = nonNullCollection(hoursOfService, InternationalString.class);
+    public InternationalString getHoursOfService() {
+        return hoursOfService;
     }
 
     /**
      * Sets time period (including time zone) when individuals can contact the organization or individual.
      *
-     * @param  newValues  the new hours of service.
+     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
+     * As of ISO 19115:2014, this singleton has been replaced by a collection.
+     * This change will tentatively be applied in GeoAPI 4.0.
+     * </div>
+     *
+     * @param  newValue  the new hours of service.
      */
-    public void setHoursOfService(final Collection<? extends InternationalString> newValues) {
-        hoursOfService = writeCollection(newValues, hoursOfService, InternationalString.class);
+    public void setHoursOfService(final InternationalString newValue) {
+        checkWritePermission(hoursOfService);
+        hoursOfService = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
index 209038f..1a01631 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
@@ -89,7 +89,7 @@
     /**
      * Name of the online resources.
      */
-    private InternationalString name;
+    private String name;
 
     /**
      * Detailed text description of what the online resource is/does.
@@ -195,20 +195,28 @@
     /**
      * Name of the online resource. Returns {@code null} if none.
      *
+     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
+     * The return type may be changed from {@code String} to {@code InternationalString} in GeoAPI 4.0.
+     * </div>
+     *
      * @return name of the online resource, or {@code null}.
      */
     @Override
     @XmlElement(name = "name")
-    public InternationalString getName() {
+    public String getName() {
         return name;
     }
 
     /**
      * Sets the name of the online resource.
      *
+     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
+     * The argument type may be changed from {@code String} to {@code InternationalString} in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new name, or {@code null} if none.
      */
-    public void setName(final InternationalString newValue) {
+    public void setName(final String newValue) {
         checkWritePermission(name);
         name = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
index 764d025..e17ed93 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
@@ -53,7 +53,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -1584743260325409070L;
+    private static final long serialVersionUID = 7061644572814855051L;
 
     /**
      * Name of the series, or aggregate dataset, of which the dataset is a part.
@@ -63,12 +63,12 @@
     /**
      * Information identifying the issue of the series.
      */
-    private InternationalString issueIdentification;
+    private String issueIdentification;
 
     /**
      * Details on which pages of the publication the article was published.
      */
-    private InternationalString page;
+    private String page;
 
     /**
      * Constructs a default series.
@@ -152,20 +152,30 @@
     /**
      * Returns information identifying the issue of the series.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return information identifying the issue of the series, or {@code null}.
      */
     @Override
     @XmlElement(name = "issueIdentification")
-    public InternationalString getIssueIdentification() {
+    public String getIssueIdentification() {
         return issueIdentification;
     }
 
     /**
      * Sets information identifying the issue of the series.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new issue identification, or {@code null} if none.
      */
-    public void setIssueIdentification(final InternationalString newValue) {
+    public void setIssueIdentification(final String newValue) {
         checkWritePermission(issueIdentification);
         issueIdentification = newValue;
     }
@@ -173,20 +183,30 @@
     /**
      * Returns details on which pages of the publication the article was published.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return details on which pages of the publication the article was published, or {@code null}.
      */
     @Override
     @XmlElement(name = "page")
-    public InternationalString getPage() {
+    public String getPage() {
         return page;
     }
 
     /**
      * Sets details on which pages of the publication the article was published.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
+     * This change will be tentatively applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new page, or {@code null} if none.
      */
-    public void setPage(final InternationalString newValue) {
+    public void setPage(final String newValue) {
         checkWritePermission(page);
         page = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
index 9d4e0fb..29e2a4a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
@@ -108,7 +108,7 @@
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
     @XmlJavaTypeAdapter(CI_Party.class),
     @XmlJavaTypeAdapter(CI_PresentationFormCode.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(CI_RoleCode.class),
     @XmlJavaTypeAdapter(CI_Series.class),
     @XmlJavaTypeAdapter(CI_Telephone.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
index c18c0b2..9597665 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
@@ -25,7 +25,7 @@
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.metadata.content.Band;
 import org.opengis.metadata.content.BandDefinition;
-import org.opengis.metadata.content.PolarisationOrientation;
+import org.opengis.metadata.content.PolarizationOrientation;
 import org.opengis.metadata.content.TransferFunctionType;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.internal.jaxb.gco.GO_Real;
@@ -69,8 +69,8 @@
     "bandBoundaryDefinition",
     "nominalSpatialResolution",
     "transferFunctionType",
-    "transmittedPolarisation",
-    "detectedPolarisation"
+    "transmittedPolarization",
+    "detectedPolarization"
 })
 @XmlRootElement(name = "MD_Band")
 @XmlSeeAlso(org.apache.sis.internal.jaxb.gmi.MI_Band.class)
@@ -78,7 +78,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 2492553738885938445L;
+    private static final long serialVersionUID = -2474871120376144737L;
 
     /**
      * Shortest wavelength that the sensor is capable of collecting within a designated band.
@@ -113,12 +113,12 @@
     /**
      * Polarization of the radiation transmitted.
      */
-    private PolarisationOrientation transmittedPolarisation;
+    private PolarizationOrientation transmittedPolarization;
 
     /**
      * Polarization of the radiation detected.
      */
-    private PolarisationOrientation detectedPolarisation;
+    private PolarizationOrientation detectedPolarization;
 
     /**
      * Constructs an initially empty band.
@@ -151,8 +151,8 @@
             peakResponse             = object.getPeakResponse();
             toneGradation            = object.getToneGradation();
             bandBoundaryDefinition   = object.getBandBoundaryDefinition();
-            transmittedPolarisation  = object.getTransmittedPolarisation();
-            detectedPolarisation     = object.getDetectedPolarisation();
+            transmittedPolarization  = object.getTransmittedPolarization();
+            detectedPolarization     = object.getDetectedPolarization();
         }
     }
 
@@ -387,42 +387,62 @@
     /**
      * Returns the polarization of the radiation transmitted.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code getTransmittedPolarization} and its return type replaced by
+     * {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
+     * for compliance with ISO 19115-2:2019.</div>
+     *
      * @return polarization of the radiation transmitted, or {@code null}.
      */
     @Override
     @XmlElement(name = "transmittedPolarisation")
-    public PolarisationOrientation getTransmittedPolarisation() {
-        return transmittedPolarisation;
+    public PolarizationOrientation getTransmittedPolarization() {
+        return transmittedPolarization;
     }
 
     /**
      * Sets the polarization of the radiation transmitted.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code setTransmittedPolarization} and its argument type replaced by
+     * {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
+     * for compliance with ISO 19115-2:2019.</div>
+     *
      * @param  newValue  the new transmitted polarization.
      */
-    public void setTransmittedPolarisation(final PolarisationOrientation newValue) {
-        checkWritePermission(transmittedPolarisation);
-        transmittedPolarisation = newValue;
+    public void setTransmittedPolarization(final PolarizationOrientation newValue) {
+        checkWritePermission(transmittedPolarization);
+        transmittedPolarization = newValue;
     }
 
     /**
      * Returns polarization of the radiation detected.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code getDetectedPolarization} and its return type replaced by
+     * {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
+     * for compliance with ISO 19115-2:2019.</div>
+     *
      * @return polarization of the radiation detected, or {@code null}.
      */
     @Override
     @XmlElement(name = "detectedPolarisation")
-    public PolarisationOrientation getDetectedPolarisation() {
-        return detectedPolarisation;
+    public PolarizationOrientation getDetectedPolarization() {
+        return detectedPolarization;
     }
 
     /**
      * Sets the polarization of the radiation detected.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code setDetectedPolarization} and its argument type replaced by
+     * {@code PolarisationOrientation} ("z" letter replaced by "s" letter) in GeoAPI 4.0
+     * for compliance with ISO 19115-2:2019.</div>
+     *
      * @param  newValue  the new detected polarization.
      */
-    public void setDetectedPolarisation(final PolarisationOrientation newValue) {
-        checkWritePermission(detectedPolarisation);
-        detectedPolarisation = newValue;
+    public void setDetectedPolarization(final PolarizationOrientation newValue) {
+        checkWritePermission(detectedPolarization);
+        detectedPolarization = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java
index 38cccd3..5c2dd6e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/package-info.java
@@ -44,7 +44,7 @@
  * {@code  ├─} {@linkplain org.opengis.metadata.content.BandDefinition          Band definition}<br>
  * {@code  ├─} {@linkplain org.opengis.metadata.content.CoverageContentType     Coverage content type}<br>
  * {@code  ├─} {@linkplain org.opengis.metadata.content.ImagingCondition        Imaging condition}<br>
- * {@code  ├─} {@linkplain org.opengis.metadata.content.PolarisationOrientation Polarisation orientation}<br>
+ * {@code  ├─} {@linkplain org.opengis.metadata.content.PolarizationOrientation Polarisation orientation}<br>
  * {@code  └─} {@linkplain org.opengis.metadata.content.TransferFunctionType    Transfer function type}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
  *                 {@linkplain org.apache.sis.metadata.iso.content.AbstractContentInformation         Content information} «abstract»<br>
@@ -57,7 +57,7 @@
  * {@code  └─}     {@linkplain org.apache.sis.metadata.iso.content.DefaultRangeElementDescription     Range element description}<br>
  *                 {@linkplain org.apache.sis.metadata.iso.content.DefaultBand                        Band}<br>
  * {@code  ├─}     {@linkplain org.opengis.metadata.content.BandDefinition                            Band definition} «code list»<br>
- * {@code  ├─}     {@linkplain org.opengis.metadata.content.PolarisationOrientation                   Polarisation orientation} «code list»<br>
+ * {@code  ├─}     {@linkplain org.opengis.metadata.content.PolarizationOrientation                   Polarisation orientation} «code list»<br>
  * {@code  └─}     {@linkplain org.opengis.metadata.content.TransferFunctionType                      Transfer function type} «code list»<br>
  *                 {@linkplain org.apache.sis.metadata.iso.content.DefaultImageDescription            Image description}<br>
  * {@code  └─}     {@linkplain org.opengis.metadata.content.ImagingCondition                          Imaging condition} «code list»<br>
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
index 76df7e2..7936548 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
@@ -22,7 +22,7 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.opengis.util.GenericName;
+import org.opengis.util.LocalName;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.distribution.DataFile;
 import org.apache.sis.xml.Namespaces;
@@ -99,7 +99,7 @@
      * This attribute may be omitted when the dataset is composed of a single file and/or the
      * data does not relate to a feature catalogue.
      */
-    private Collection<GenericName> featureTypes;
+    private Collection<LocalName> featureTypes;
 
     /**
      * Defines the format of the transfer data file.
@@ -130,7 +130,7 @@
             fileName        = object.getFileName();
             fileDescription = object.getFileDescription();
             fileType        = object.getFileType();
-            featureTypes    = copyCollection(object.getFeatureTypes(), GenericName.class);
+            featureTypes    = copyCollection(object.getFeatureTypes(), LocalName.class);
             fileFormat      = object.getFileFormat();
         }
     }
@@ -249,8 +249,8 @@
      */
     @Override
     @XmlElement(name = "featureTypes")
-    public Collection<GenericName> getFeatureTypes() {
-        return featureTypes = nonNullCollection(featureTypes, GenericName.class);
+    public Collection<LocalName> getFeatureTypes() {
+        return featureTypes = nonNullCollection(featureTypes, LocalName.class);
     }
 
     /**
@@ -258,8 +258,8 @@
      *
      * @param newValues  the new feature type values.
      */
-    public void setFeatureTypes(final Collection<? extends GenericName> newValues) {
-        featureTypes = writeCollection(newValues, featureTypes, GenericName.class);
+    public void setFeatureTypes(final Collection<? extends LocalName> newValues) {
+        featureTypes = writeCollection(newValues, featureTypes, LocalName.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
index 60f1d00..1857bb1 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
@@ -20,7 +20,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.distribution.Distributor;
 import org.opengis.metadata.distribution.StandardOrderProcess;
@@ -70,12 +70,12 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -8819538342342106743L;
+    private static final long serialVersionUID = 5706757156163948001L;
 
     /**
      * Party from whom the resource may be obtained. This list need not be exhaustive.
      */
-    private Responsibility distributorContact;
+    private ResponsibleParty distributorContact;
 
     /**
      * Provides information about how the resource may be obtained, and related
@@ -104,7 +104,7 @@
      *
      * @param distributorContact  party from whom the resource may be obtained, or {@code null}.
      */
-    public DefaultDistributor(final Responsibility distributorContact) {
+    public DefaultDistributor(final ResponsibleParty distributorContact) {
         this.distributorContact = distributorContact;
     }
 
@@ -155,20 +155,30 @@
     /**
      * Party from whom the resource may be obtained.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return party from whom the resource may be obtained, or {@code null}.
      */
     @Override
     @XmlElement(name = "distributorContact", required = true)
-    public Responsibility getDistributorContact() {
+    public ResponsibleParty getDistributorContact() {
         return distributorContact;
     }
 
     /**
      * Sets the party from whom the resource may be obtained.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new distributor contact.
      */
-    public void setDistributorContact(final Responsibility newValue) {
+    public void setDistributorContact(final ResponsibleParty newValue) {
         checkWritePermission(distributorContact);
         distributorContact = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
index 4f10fc0..685400c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
@@ -28,18 +28,20 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.distribution.Medium;
+import org.opengis.metadata.distribution.MediumName;
 import org.opengis.metadata.distribution.MediumFormat;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.internal.jaxb.gco.GO_Real;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.jaxb.metadata.CI_Citation;
 import org.apache.sis.internal.jaxb.metadata.MD_Identifier;
-import org.apache.sis.internal.metadata.legacy.MediumName;
 import org.apache.sis.internal.metadata.Dependencies;
 import org.apache.sis.internal.metadata.legacy.LegacyPropertyAdapter;
 import org.apache.sis.internal.xml.LegacyNamespaces;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.util.CodeLists;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
@@ -72,7 +74,7 @@
 @XmlType(name = "MD_Medium_Type", propOrder = {
     "identifier",           // New in ISO 19115-3
     "name",
-    "legacyName",           // From ISO 19115:2003
+    "newName",              // From ISO 19115:2014
     "density",
     "densities",
     "densityUnits",
@@ -85,12 +87,12 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -460355952171320089L;
+    private static final long serialVersionUID = 2657393801067168091L;
 
     /**
      * Name of the medium on which the resource can be received.
      */
-    private Citation name;
+    private MediumName name;
 
     /**
      * Density at which the data is recorded.
@@ -181,21 +183,31 @@
     /**
      * Returns the name of the medium on which the resource can be received.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * {@link MediumName} may be replaced by {@link Citation} in GeoAPI 4.0.
+     * </div>
+     *
      * @return name of the medium, or {@code null}.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-389">SIS-389</a>
+     *
      */
     @Override
-    @XmlElement(name = "name")
-    @XmlJavaTypeAdapter(CI_Citation.Since2014.class)
-    public Citation getName() {
-        return name;
+    @XmlElement(name = "name", namespace = LegacyNamespaces.GMD)
+    public MediumName getName() {
+        return FilterByVersion.LEGACY_METADATA.accept() ? name : null;
     }
 
     /**
      * Sets the name of the medium on which the resource can be received.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * {@link MediumName} may be replaced by {@link Citation} in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValue  the new name.
      */
-    public void setName(final Citation newValue) {
+    public void setName(final MediumName newValue) {
         checkWritePermission(name);
         name = newValue;
     }
@@ -407,15 +419,21 @@
     /**
      * Returns the medium name as a code list.
      */
-    @XmlElement(name = "name", namespace = LegacyNamespaces.GMD)
-    private MediumName getLegacyName() {
-        return FilterByVersion.LEGACY_METADATA.accept() ? MediumName.castOrWrap(name) : null;
+    @XmlElement(name = "name")
+    @XmlJavaTypeAdapter(CI_Citation.Since2014.class)
+    private Citation getNewName() {
+        return (name != null) ? new DefaultCitation(name.name()) : null;
     }
 
     /**
      * Sets the name of the medium on which the resource can be received.
      */
-    private void setLegacyName(final MediumName newValue) {
-        name = newValue;
+    private void setNewName(final Citation newValue) {
+        if (newValue != null) {
+            final InternationalString title = newValue.getTitle();
+            if (title != null) {
+                name = CodeLists.forName(MediumName.class, title.toString(), false);
+            }
+        }
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
index f391908..ed77db8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
@@ -38,6 +38,7 @@
  * {@code  ├─} {@linkplain org.apache.sis.metadata.iso.distribution.DefaultDigitalTransferOptions Digital transfer options}<br>
  * {@code  └─} {@linkplain org.apache.sis.metadata.iso.distribution.DefaultDataFile               Data file}<br>
  * {@linkplain org.opengis.util.CodeList Code list}<br>
+ * {@code  ├─} {@linkplain org.opengis.metadata.distribution.MediumName   Medium name}<br>
  * {@code  └─} {@linkplain org.opengis.metadata.distribution.MediumFormat Medium format}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
  *                     {@linkplain org.apache.sis.metadata.iso.distribution.DefaultDistribution           Distribution}<br>
@@ -46,6 +47,7 @@
  * {@code  │   └─}     {@linkplain org.apache.sis.metadata.iso.distribution.DefaultStandardOrderProcess   Standard order process}<br>
  * {@code  └─}         {@linkplain org.apache.sis.metadata.iso.distribution.DefaultDigitalTransferOptions Digital transfer options}<br>
  * {@code      └─}     {@linkplain org.apache.sis.metadata.iso.distribution.DefaultMedium                 Medium}<br>
+ * {@code          ├─} {@linkplain org.opengis.metadata.distribution.MediumName                           Medium name} «code list»<br>
  * {@code          └─} {@linkplain org.opengis.metadata.distribution.MediumFormat                         Medium format} «code list»<br>
  *                     {@linkplain org.apache.sis.metadata.iso.distribution.DefaultDataFile               Data file}<br>
  * </td></tr></table>
@@ -95,6 +97,7 @@
     @XmlJavaTypeAdapter(MD_Medium.class),
     @XmlJavaTypeAdapter(MD_MediumFormatCode.class),
     @XmlJavaTypeAdapter(MD_MediumNameCode.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(MD_StandardOrderProcess.class),
 
     // Java types, primitive types and basic OGC types handling
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
index 5937d16..9faa069 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
@@ -24,7 +24,7 @@
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.extent.Extent;
@@ -144,7 +144,7 @@
     /**
      * Recognition of those who contributed to the resource(s).
      */
-    private Collection<InternationalString> credits;
+    private Collection<String> credits;
 
     /**
      * Status of the resource(s).
@@ -155,7 +155,7 @@
      * Identification of, and means of communication with, person(s) and organizations(s)
      * associated with the resource(s).
      */
-    private Collection<Responsibility> pointOfContacts;
+    private Collection<ResponsibleParty> pointOfContacts;
 
     /**
      * Methods used to spatially represent geographic information.
@@ -260,9 +260,9 @@
             citation                   = object.getCitation();
             abstracts                  = object.getAbstract();
             purpose                    = object.getPurpose();
-            credits                    = copyCollection(object.getCredits(), InternationalString.class);
+            credits                    = copyCollection(object.getCredits(), String.class);
             status                     = copyCollection(object.getStatus(), Progress.class);
-            pointOfContacts            = copyCollection(object.getPointOfContacts(), Responsibility.class);
+            pointOfContacts            = copyCollection(object.getPointOfContacts(), ResponsibleParty.class);
             spatialRepresentationTypes = copyCollection(object.getSpatialRepresentationTypes(), SpatialRepresentationType.class);
             spatialResolutions         = copyCollection(object.getSpatialResolutions(), Resolution.class);
             temporalResolutions        = copyCollection(object.getTemporalResolutions(), Duration.class);
@@ -383,21 +383,29 @@
     /**
      * Returns the recognition of those who contributed to the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type may be changed to the {@code InternationalString} interface in GeoAPI 4.0.
+     * </div>
+     *
      * @return recognition of those who contributed to the resource(s).
      */
     @Override
     @XmlElement(name = "credit")
-    public Collection<InternationalString> getCredits() {
-        return credits = nonNullCollection(credits, InternationalString.class);
+    public Collection<String> getCredits() {
+        return credits = nonNullCollection(credits, String.class);
     }
 
     /**
      * Sets the recognition of those who contributed to the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type may be changed to the {@code InternationalString} interface in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new credits.
      */
-    public void setCredits(final Collection<? extends InternationalString> newValues) {
-        credits = writeCollection(newValues, credits, InternationalString.class);
+    public void setCredits(final Collection<? extends String> newValues) {
+        credits = writeCollection(newValues, credits, String.class);
     }
 
     /**
@@ -424,23 +432,33 @@
      * Returns the identification of, and means of communication with, person(s) and organizations(s)
      * associated with the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return means of communication with person(s) and organizations(s) associated with the resource(s).
      *
      * @see org.apache.sis.metadata.iso.DefaultMetadata#getContacts()
      */
     @Override
     @XmlElement(name = "pointOfContact")
-    public Collection<Responsibility> getPointOfContacts() {
-        return pointOfContacts = nonNullCollection(pointOfContacts, Responsibility.class);
+    public Collection<ResponsibleParty> getPointOfContacts() {
+        return pointOfContacts = nonNullCollection(pointOfContacts, ResponsibleParty.class);
     }
 
     /**
      * Sets the means of communication with persons(s) and organizations(s) associated with the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new points of contacts.
      */
-    public void setPointOfContacts(final Collection<? extends Responsibility> newValues) {
-        pointOfContacts = writeCollection(newValues, pointOfContacts, Responsibility.class);
+    public void setPointOfContacts(final Collection<? extends ResponsibleParty> newValues) {
+        pointOfContacts = writeCollection(newValues, pointOfContacts, ResponsibleParty.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
index 118fa33..d8bd253 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
@@ -21,11 +21,13 @@
 import java.util.Collections;
 import java.util.Locale;
 import java.nio.charset.Charset;
+import java.util.stream.Collectors;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.metadata.identification.CharacterSet;
 import org.opengis.metadata.identification.TopicCategory;
 import org.opengis.metadata.identification.DataIdentification;
 import org.apache.sis.internal.jaxb.lan.LocaleAndCharset;
@@ -74,7 +76,7 @@
  */
 @XmlType(name = "MD_DataIdentification_Type", propOrder = {
     "languages",                // Legacy ISO 19115:2003
-    "characterSets",            // Legacy ISO 19115:2003
+    "characterSet",             // Legacy ISO 19115:2003
     "defaultLocale",            // New in ISO 19115:2014
     "otherLocales",             // New in ISO 19115:2014
     "environmentDescription",
@@ -245,6 +247,10 @@
     /**
      * Returns the character coding standard used for the dataset.
      *
+     * <div class="warning"><b>Upcoming API change — JDK integration</b><br>
+     * The element type may change to the {@link Charset} class in GeoAPI 4.0.
+     * </div>
+     *
      * @return character coding standard(s) used.
      *
      * @deprecated Replaced by {@code getLocalesAndCharsets().values()}.
@@ -252,22 +258,30 @@
     @Override
     @Deprecated
     @Dependencies("getLocalesAndCharsets")
-    @XmlElement(name = "characterSet", namespace = LegacyNamespaces.GMD)
-    public Collection<Charset> getCharacterSets() {
-        return FilterByVersion.LEGACY_METADATA.accept() ? LocaleAndCharset.getCharacterSets(getLocalesAndCharsets()) : null;
+    // @XmlElement at the end of this class.
+    public Collection<CharacterSet> getCharacterSets() {
+        return getLocalesAndCharsets().values().stream().map(CharacterSet::fromCharset).collect(Collectors.toSet());
     }
 
     /**
      * Sets the character coding standard used for the dataset.
      *
+     * <div class="warning"><b>Upcoming API change — JDK integration</b><br>
+     * The element type may change to the {@link Charset} class in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new character sets.
      *
      * @deprecated Replaced by putting values in {@link #getLocalesAndCharsets()} map.
      */
     @Deprecated
-    public void setCharacterSets(final Collection<? extends Charset> newValues) {
+    public void setCharacterSets(final Collection<? extends CharacterSet> newValues) {
         // TODO: delete after SIS 1.0 release (method not needed by JAXB).
-        setLocalesAndCharsets(LocaleAndCharset.setCharacterSets(getLocalesAndCharsets(), newValues));
+        Collection<Charset> c = null;
+        if (newValues != null) {
+            c = newValues.stream().map(CharacterSet::toCharset).collect(Collectors.toSet());
+        }
+        setLocalesAndCharsets(LocaleAndCharset.setCharacterSets(getLocalesAndCharsets(), c));
     }
 
     /**
@@ -350,4 +364,14 @@
     private Collection<PT_Locale> getOtherLocales() {
         return FilterByVersion.CURRENT_METADATA.accept() ? OtherLocales.filter(getLocalesAndCharsets()) : null;
     }
+
+    /**
+     * Returns the character coding for the metadata set (used in legacy ISO 19157 format).
+     *
+     * @see #getCharacterSets()
+     */
+    @XmlElement(name = "characterSet", namespace = LegacyNamespaces.GMD)
+    private Collection<Charset> getCharacterSet() {
+        return FilterByVersion.LEGACY_METADATA.accept() ? LocaleAndCharset.getCharacterSets(getLocalesAndCharsets()) : null;
+    }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
index 6a33e8f..eadaf03 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
@@ -23,7 +23,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.identification.Usage;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.metadata.iso.ISOMetadata;
@@ -102,7 +102,7 @@
     /**
      * Identification of and means of communicating with person(s) and organization(s) using the resource(s).
      */
-    private Collection<Responsibility> userContactInfo;
+    private Collection<ResponsibleParty> userContactInfo;
 
     /**
      * Responses to the user-determined limitations.
@@ -133,10 +133,10 @@
      * @param userContactInfo  means of communicating with person(s) and organization(s), or {@code null} if none.
      */
     public DefaultUsage(final CharSequence specificUsage,
-                        final Responsibility userContactInfo)
+                        final ResponsibleParty userContactInfo)
     {
         this.specificUsage   = Types.toInternationalString(specificUsage);
-        this.userContactInfo = singleton(userContactInfo, Responsibility.class);
+        this.userContactInfo = singleton(userContactInfo, ResponsibleParty.class);
     }
 
     /**
@@ -154,7 +154,7 @@
             specificUsage             = object.getSpecificUsage();
             usageDate                 = toMilliseconds(object.getUsageDate());
             userDeterminedLimitations = object.getUserDeterminedLimitations();
-            userContactInfo           = copyCollection(object.getUserContactInfo(), Responsibility.class);
+            userContactInfo           = copyCollection(object.getUserContactInfo(), ResponsibleParty.class);
             responses                 = copyCollection(object.getResponses(), InternationalString.class);
             additionalDocumentation   = copyCollection(object.getAdditionalDocumentation(), Citation.class);
             identifiedIssues          = copyCollection(object.getIdentifiedIssues(), Citation.class);
@@ -252,21 +252,31 @@
     /**
      * Returns identification of and means of communicating with person(s) and organization(s) using the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return means of communicating with person(s) and organization(s) using the resource(s).
      */
     @Override
     @XmlElement(name = "userContactInfo")
-    public Collection<Responsibility> getUserContactInfo() {
-        return userContactInfo = nonNullCollection(userContactInfo, Responsibility.class);
+    public Collection<ResponsibleParty> getUserContactInfo() {
+        return userContactInfo = nonNullCollection(userContactInfo, ResponsibleParty.class);
     }
 
     /**
      * Sets identification of and means of communicating with person(s) and organization(s) using the resource(s).
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new user contact info.
      */
-    public void setUserContactInfo(final Collection<? extends Responsibility> newValues) {
-        userContactInfo = writeCollection(newValues, userContactInfo, Responsibility.class);
+    public void setUserContactInfo(final Collection<? extends ResponsibleParty> newValues) {
+        userContactInfo = writeCollection(newValues, userContactInfo, ResponsibleParty.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
index 61e0ecc..3cac3b8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
@@ -115,7 +115,7 @@
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(DCPList.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
index 22ee8f8..87bfc9a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
@@ -26,7 +26,7 @@
 import org.opengis.util.InternationalString;
 import org.opengis.temporal.TemporalPrimitive;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.maintenance.Scope;
 import org.opengis.metadata.lineage.Source;
 import org.opengis.metadata.lineage.Processing;
@@ -109,7 +109,7 @@
      * Identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      */
-    private Collection<Responsibility> processors;
+    private Collection<ResponsibleParty> processors;
 
     /**
      * Process step documentation.
@@ -173,7 +173,7 @@
             description           = object.getDescription();
             rationale             = object.getRationale();
             stepDateTime          = TemporalUtilities.createInstant(object.getDate());
-            processors            = copyCollection(object.getProcessors(), Responsibility.class);
+            processors            = copyCollection(object.getProcessors(), ResponsibleParty.class);
             references            = copyCollection(object.getReferences(), Citation.class);
             sources               = copyCollection(object.getSources(), Source.class);
             scope                 = object.getScope();
@@ -305,22 +305,32 @@
      * Returns the identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return means of communication with person(s) and organization(s) associated with the process step.
      */
     @Override
     @XmlElement(name = "processor")
-    public Collection<Responsibility> getProcessors() {
-        return processors = nonNullCollection(processors, Responsibility.class);
+    public Collection<ResponsibleParty> getProcessors() {
+        return processors = nonNullCollection(processors, ResponsibleParty.class);
     }
 
     /**
      * Identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new processors.
      */
-    public void setProcessors(final Collection<? extends Responsibility> newValues) {
-        processors = writeCollection(newValues, processors, Responsibility.class);
+    public void setProcessors(final Collection<? extends ResponsibleParty> newValues) {
+        processors = writeCollection(newValues, processors, ResponsibleParty.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
index 78181f9..f5782b3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
@@ -80,7 +80,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_Real.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java
new file mode 100644
index 0000000..6db039e
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.iso.maintenance;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.feature.type.AttributeType;
+import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
+
+
+/**
+ * For (un)marshalling deprecated {@link AttributeType} as a character string,
+ * as expected by ISO 19115-3:2016. This is a temporary bridge to be removed
+ * after the GeoAPI interfaces has been upgraded to ISO 19115-1:2014 model.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+final class AttributeTypeAdapter extends XmlAdapter<GO_CharacterString, AttributeType> {
+    /**
+     * Wrap the given value from {@link DefaultScopeDescription} to the elements
+     * defined by ISO 19115-3:2016 schema.
+     */
+    @Override
+    public AttributeType unmarshal(GO_CharacterString value) {
+        return new LegacyFeatureType(LegacyFeatureType.ADAPTER.unmarshal(value));
+    }
+
+    /**
+     * Unwrap the elements defined by ISO 19115-3:2016 schema to the value used by
+     * {@link DefaultScopeDescription}.
+     */
+    @Override
+    public GO_CharacterString marshal(AttributeType value) {
+        return LegacyFeatureType.ADAPTER.marshal(LegacyFeatureType.wrap(value));
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
index ddba30f..6d33e52 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
@@ -25,7 +25,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.CitationDate;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.maintenance.MaintenanceFrequency;
 import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.maintenance.ScopeCode;
@@ -118,7 +118,7 @@
      * Identification of, and means of communicating with, person(s) and organization(s)
      * with responsibility for maintaining the resource.
      */
-    private Collection<Responsibility> contacts;
+    private Collection<ResponsibleParty> contacts;
 
     /**
      * Creates a an initially empty maintenance information.
@@ -153,7 +153,7 @@
             userDefinedMaintenanceFrequency = object.getUserDefinedMaintenanceFrequency();
             maintenanceScopes               = copyCollection(object.getMaintenanceScopes(), Scope.class);
             maintenanceNotes                = copyCollection(object.getMaintenanceNotes(), InternationalString.class);
-            contacts                        = copyCollection(object.getContacts(), Responsibility.class);
+            contacts                        = copyCollection(object.getContacts(), ResponsibleParty.class);
         }
     }
 
@@ -469,24 +469,34 @@
      * Returns identification of, and means of communicating with,
      * person(s) and organization(s) with responsibility for maintaining the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @return means of communicating with person(s) and organization(s) with responsibility
      *         for maintaining the resource.
      */
     @Override
     @XmlElement(name = "contact")
-    public Collection<Responsibility> getContacts() {
-        return contacts = nonNullCollection(contacts, Responsibility.class);
+    public Collection<ResponsibleParty> getContacts() {
+        return contacts = nonNullCollection(contacts, ResponsibleParty.class);
     }
 
     /**
      * Sets identification of, and means of communicating with,
      * person(s) and organization(s) with responsibility for maintaining the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
+     * This change may be applied in GeoAPI 4.0.
+     * </div>
+     *
      * @param  newValues  the new identification of person(s) and organization(s)
      *                    with responsibility for maintaining the resource.
      */
-    public void setContacts(final Collection<? extends Responsibility> newValues) {
-        contacts = writeCollection(newValues, contacts, Responsibility.class);
+    public void setContacts(final Collection<? extends ResponsibleParty> newValues) {
+        contacts = writeCollection(newValues, contacts, ResponsibleParty.class);
     }
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
index e78783d..3e97914 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
@@ -30,11 +30,14 @@
 import org.apache.sis.internal.system.Semaphores;
 import org.apache.sis.util.collection.CheckedContainer;
 import org.apache.sis.util.resources.Messages;
-import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 
+// Branch-dependent imports
+import org.opengis.feature.type.AttributeType;
+import org.opengis.feature.type.FeatureType;
+
 
 /**
  * Description of the class of information covered by the information.
@@ -117,12 +120,12 @@
      * The value, as one of the following types:
      *
      * <ul>
-     *   <li>{@code Set<CharSequence>}   for the {@code features} property</li>
-     *   <li>{@code Set<CharSequence>}   for the {@code attributes} property</li>
-     *   <li>{@code Set<CharSequence>}   for the {@code featureInstances} property</li>
-     *   <li>{@code Set<CharSequence>}   for the {@code attributeInstances} property</li>
-     *   <li>{@code String}              for the {@code dataset} property</li>
-     *   <li>{@code InternationalString} for the {@code other} property</li>
+     *   <li>{@code Set<FeatureType>}   for the {@code features} property</li>
+     *   <li>{@code Set<AttributeType>} for the {@code attributes} property</li>
+     *   <li>{@code Set<FeatureType>}   for the {@code featureInstances} property</li>
+     *   <li>{@code Set<AttributeType>} for the {@code attributeInstances} property</li>
+     *   <li>{@code String} for the {@code dataset} property</li>
+     *   <li>{@code String} for the {@code other} property</li>
      * </ul>
      */
     private Object value;
@@ -151,27 +154,36 @@
      *
      * @see #castOrCopy(ScopeDescription)
      */
+    @SuppressWarnings("unchecked")
     public DefaultScopeDescription(final ScopeDescription object) {
         super(object);
         if (object != null) {
             for (byte i=DATASET; i<=OTHER; i++) {
-                Collection<? extends CharSequence> props = null;
-                Object value = null;
+                Object candidate;
                 switch (i) {
-                    case DATASET:             value = object.getDataset();            break;
-                    case FEATURES:            props = object.getFeatures();           break;
-                    case ATTRIBUTES:          props = object.getAttributes();         break;
-                    case FEATURE_INSTANCES:   props = object.getFeatureInstances();   break;
-                    case ATTRIBUTE_INSTANCES: props = object.getAttributeInstances(); break;
-                    case OTHER:               value = object.getOther();              break;
+                    case DATASET:             candidate = object.getDataset();            break;
+                    case FEATURES:            candidate = object.getFeatures();           break;
+                    case ATTRIBUTES:          candidate = object.getAttributes();         break;
+                    case FEATURE_INSTANCES:   candidate = object.getFeatureInstances();   break;
+                    case ATTRIBUTE_INSTANCES: candidate = object.getAttributeInstances(); break;
+                    case OTHER:               candidate = object.getOther();              break;
                     default: throw new AssertionError(i);
                 }
-                if (props != null) {
-                    value = copySet(props, CharSequence.class);
-                }
-                if (value != null) {
-                    this.value = value;
-                    this.property = i;
+                if (candidate != null) {
+                    switch (i) {
+                        case ATTRIBUTES:
+                        case ATTRIBUTE_INSTANCES: {
+                            candidate = copySet((Collection<AttributeType>) candidate, AttributeType.class);
+                            break;
+                        }
+                        case FEATURES:
+                        case FEATURE_INSTANCES: {
+                            candidate = copySet((Collection<FeatureType>) candidate, FeatureType.class);
+                            break;
+                        }
+                    }
+                    value = candidate;
+                    property = i;
                     break;
                 }
             }
@@ -204,34 +216,36 @@
     }
 
     /**
-     * Returns the given value casted to a {@code Set<CharSequence>}.
+     * Returns the given value casted to a {@code Set} of elements of the given type.
+     * It is caller responsibility to ensure that the cast is valid, as element type
+     * is verified only when assertions are enabled.
      */
     @SuppressWarnings("unchecked")
-    private static Set<CharSequence> cast(final Object value) {
+    private static <E> Set<E> cast(final Object value, final Class<E> type) {
         assert !(value instanceof CheckedContainer<?>) ||
-                ((CheckedContainer<?>) value).getElementType() == CharSequence.class;
-        return (Set<CharSequence>) value;
+                ((CheckedContainer<?>) value).getElementType() == type;
+        return (Set<E>) value;
     }
 
     /**
      * Returns the set of properties identified by the {@code code} argument,
      * or an unmodifiable empty set if another value is defined.
      */
-    private Set<CharSequence> getProperty(final byte code) {
+    private <E> Set<E> getProperty(final Class<E> type, final byte code) {
         final Object value = this.value;
         if (value != null) {
             if (property == code) {
-                return cast(value);
+                return cast(value, type);
             } else if (!(value instanceof Set) || !((Set<?>) value).isEmpty()) {
                 return Semaphores.query(Semaphores.NULL_COLLECTION)
-                       ? null : new ExcludedSet<>(NAMES[code-1], NAMES[property-1]);
+                       ? null : new ExcludedSet<E>(NAMES[code-1], NAMES[property-1]);
             }
         }
         /*
          * Unconditionally create a new set, because the
          * user may hold a reference to the previous one.
          */
-        final Set<CharSequence> c = nonNullSet(null, CharSequence.class);
+        final Set<E> c = nonNullSet(null, type);
         property = code;
         this.value = c;
         return c;
@@ -244,17 +258,17 @@
      * @param newValue  the value to set.
      * @param code      the property which is going to be set.
      */
-    private void setProperty(final Set<? extends CharSequence> newValue, final byte code) {
-        Set<CharSequence> c = null;
+    private <E> void setProperty(final Set<? extends E> newValue, final Class<E> type, final byte code) {
+        Set<E> c = null;
         if (property == code) {
-            c = cast(value);
+            c = cast(value, type);
         } else if (isNullOrEmpty(newValue)) {
             return;
         } else {
             warningOnOverwrite(code);
             property = code;
         }
-        value = writeSet(newValue, c, CharSequence.class);
+        value = writeSet(newValue, c, type);
     }
 
     /**
@@ -349,12 +363,16 @@
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @return feature types to which the information applies.
      */
     @Override
     @XmlElement(name = "features")
-    public Set<CharSequence> getFeatures() {
-        return getProperty(FEATURES);
+    public Set<FeatureType> getFeatures() {
+        return getProperty(FeatureType.class, FEATURES);
     }
 
     /**
@@ -364,10 +382,14 @@
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @param  newValues  the new feature types.
      */
-    public void setFeatures(final Set<? extends CharSequence> newValues) {
-        setProperty(newValues, FEATURES);
+    public void setFeatures(final Set<? extends FeatureType> newValues) {
+        setProperty(newValues, FeatureType.class, FEATURES);
     }
 
     /**
@@ -383,12 +405,16 @@
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @return attribute types to which the information applies.
      */
     @Override
     @XmlElement(name = "attributes")
-    public Set<CharSequence> getAttributes() {
-        return getProperty(ATTRIBUTES);
+    public Set<AttributeType> getAttributes() {
+        return getProperty(AttributeType.class, ATTRIBUTES);
     }
 
     /**
@@ -398,10 +424,14 @@
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @param  newValues  the new attribute types.
      */
-    public void setAttributes(final Set<? extends CharSequence> newValues) {
-        setProperty(newValues, ATTRIBUTES);
+    public void setAttributes(final Set<? extends AttributeType> newValues) {
+        setProperty(newValues, AttributeType.class, ATTRIBUTES);
     }
 
     /**
@@ -417,12 +447,16 @@
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @return feature instances to which the information applies.
      */
     @Override
     @XmlElement(name = "featureInstances")
-    public Set<CharSequence> getFeatureInstances() {
-        return getProperty(FEATURE_INSTANCES);
+    public Set<FeatureType> getFeatureInstances() {
+        return getProperty(FeatureType.class, FEATURE_INSTANCES);
     }
 
     /**
@@ -432,10 +466,14 @@
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @param  newValues  the new feature instances.
      */
-    public void setFeatureInstances(final Set<? extends CharSequence> newValues) {
-        setProperty(newValues, FEATURE_INSTANCES);
+    public void setFeatureInstances(final Set<? extends FeatureType> newValues) {
+        setProperty(newValues, FeatureType.class, FEATURE_INSTANCES);
     }
 
     /**
@@ -451,12 +489,16 @@
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @return attribute instances to which the information applies.
      */
     @Override
     @XmlElement(name = "attributeInstances")
-    public Set<CharSequence> getAttributeInstances() {
-        return getProperty(ATTRIBUTE_INSTANCES);
+    public Set<AttributeType> getAttributeInstances() {
+        return getProperty(AttributeType.class, ATTRIBUTE_INSTANCES);
     }
 
     /**
@@ -466,21 +508,29 @@
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
+     *
      * @param  newValues  the new attribute instances.
      */
-    public void setAttributeInstances(final Set<? extends CharSequence> newValues) {
-        setProperty(newValues, ATTRIBUTE_INSTANCES);
+    public void setAttributeInstances(final Set<? extends AttributeType> newValues) {
+        setProperty(newValues, AttributeType.class, ATTRIBUTE_INSTANCES);
     }
 
     /**
      * Returns the class of information that does not fall into the other categories to which the information applies.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@link InternationalString} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-221">GEO-221</a> for more information.</div>
+     *
      * @return class of information that does not fall into the other categories, or {@code null}.
      */
     @Override
     @XmlElement(name = "other")
-    public InternationalString getOther() {
-        return (property == OTHER) ? (InternationalString) value : null;
+    public String getOther() {
+        return (property == OTHER) ? (String) value : null;
     }
 
     /**
@@ -491,9 +541,13 @@
      * If and only if the {@code newValue} is non-null, then this method automatically
      * discards all other properties.
      *
+     * <div class="warning"><b>Upcoming API change:</b>
+     * The type of this property may be changed to {@link InternationalString} for ISO 19115:2014 conformance.
+     * See <a href="http://jira.codehaus.org/browse/GEO-221">GEO-221</a> for more information.</div>
+     *
      * @param newValue Other class of information.
      */
-    public void setOther(final InternationalString newValue) {
+    public void setOther(final String newValue) {
         checkWritePermission(value);
         if (newValue != null || property == OTHER) {
             warningOnOverwrite(OTHER);
@@ -527,19 +581,21 @@
             }
             setDataset(description);
         } else if (ScopeCode.FEATURE_TYPE.equals(level)) {
-            setFeatures(newValues);
+            setFeatures(LegacyFeatureType.wrapAll(newValues));
         } else if (ScopeCode.ATTRIBUTE_TYPE.equals(level)) {
-            setAttributes(newValues);
+            setAttributes(LegacyFeatureType.wrapAll(newValues));
         } else if (ScopeCode.FEATURE.equals(level)) {
-            setFeatureInstances(newValues);
+            setFeatureInstances(LegacyFeatureType.wrapAll(newValues));
         } else if (ScopeCode.ATTRIBUTE.equals(level)) {
-            setAttributeInstances(newValues);
+            setAttributeInstances(LegacyFeatureType.wrapAll(newValues));
         } else {
-            InternationalString description = null;
+            String description = null;
             if (newValues != null) {
                 for (CharSequence value : newValues) {
-                    description = Types.toInternationalString(value);
-                    if (description != null) break;
+                    if (value != null) {
+                        description = value.toString();
+                        break;
+                    }
                 }
             }
             setOther(description);
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java
new file mode 100644
index 0000000..af1eb36
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.iso.maintenance;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.feature.type.FeatureType;
+import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
+
+
+/**
+ * For (un)marshalling deprecated {@link FeatureType} as a character string,
+ * as expected by ISO 19115-3:2016. This is a temporary bridge to be removed
+ * after the GeoAPI interfaces has been upgraded to ISO 19115-1:2014 model.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+final class FeatureTypeAdapter extends XmlAdapter<GO_CharacterString, FeatureType> {
+    /**
+     * Wrap the given value from {@link DefaultScopeDescription} to the elements
+     * defined by ISO 19115-3:2016 schema.
+     */
+    @Override
+    public FeatureType unmarshal(GO_CharacterString value) {
+        return new LegacyFeatureType(LegacyFeatureType.ADAPTER.unmarshal(value));
+    }
+
+    /**
+     * Unwrap the elements defined by ISO 19115-3:2016 schema to the value used by
+     * {@link DefaultScopeDescription}.
+     */
+    @Override
+    public GO_CharacterString marshal(FeatureType value) {
+        return LegacyFeatureType.ADAPTER.marshal(LegacyFeatureType.wrap(value));
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyFeatureType.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyFeatureType.java
new file mode 100644
index 0000000..8b177af
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyFeatureType.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.metadata.iso.maintenance;
+
+import java.util.Set;
+import java.util.LinkedHashSet;
+import org.opengis.feature.type.FeatureType;
+import org.opengis.feature.type.AttributeType;
+import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
+import org.apache.sis.util.ArgumentChecks;
+
+
+/**
+ * Bridges between deprecated {@link FeatureType} / {@link AttributeType} and {@link CharSequence}.
+ * {@code FeatureType} and {@code AttributeType} were used in ISO 19115:2003, but have been replaced
+ * by {@link CharSequence} in ISO 19115:2014. The corresponding GeoAPI 3.0 interfaces are empty since
+ * they were placeholder for future work. We use this {@code LegacyFeatureType} as a temporary bridge,
+ * to be removed with GeoAPI 4.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ *
+ * @deprecated To be removed after migration to GeoAPI 4.0.
+ */
+@Deprecated
+public final class LegacyFeatureType implements FeatureType, AttributeType, CharSequence {
+    /**
+     * The adapter doing most of the actual work of converting {@code FeatureType} or {@code AttributeType}
+     * to {@code <gco:CharacterSequence>} elements.
+     */
+    static final CharSequenceAdapter ADAPTER = new CharSequenceAdapter();
+
+    /**
+     * The value to wrap as a {@code FeatureType} or {@code AttributeType}.
+     */
+    private final CharSequence value;
+
+    /**
+     * Creates a new type for the given value, which must be non-null.
+     *
+     * @param  value  the text to wrap in a legacy feature type.
+     */
+    public LegacyFeatureType(final CharSequence value) {
+        ArgumentChecks.ensureNonNull("value", value);
+        this.value = value;
+    }
+
+    /**
+     * Wraps the given {@code FeatureType} or {@code AttributeType} as a {@code CharSequence}.
+     */
+    static CharSequence wrap(final Object value) {
+        return (value == null || value instanceof CharSequence)
+                ? (CharSequence) value : new LegacyFeatureType(value.toString());
+    }
+
+    /**
+     * Returns a list with all content of the given collection wrapped as {@link LegacyFeatureType}.
+     */
+    static Set<LegacyFeatureType> wrapAll(final Iterable<? extends CharSequence> values) {
+        if (values == null) {
+            return null;
+        }
+        final Set<LegacyFeatureType> wrapped = new LinkedHashSet<>();
+        for (final CharSequence value : values) {
+            wrapped.add((value == null || value instanceof LegacyFeatureType)
+                        ? (LegacyFeatureType) value : new LegacyFeatureType(value));
+        }
+        return wrapped;
+    }
+
+    /**
+     * Delegates to the value given at construction time.
+     */
+    @Override public int          length()                        {return value.length();}
+    @Override public char         charAt(int index)               {return value.charAt(index);}
+    @Override public CharSequence subSequence(int start, int end) {return value.subSequence(start, end);}
+    @Override public String       toString()                      {return value.toString();}
+    @Override public int          hashCode()                      {return value.hashCode() ^ 439703003;}
+    @Override public boolean      equals(final Object obj) {
+        return (obj instanceof LegacyFeatureType) && value.equals(((LegacyFeatureType) obj).value);
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
index 30b4edb..d6b57f9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
@@ -77,7 +77,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Date.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(MD_MaintenanceFrequencyCode.class),
@@ -87,6 +87,8 @@
     @XmlJavaTypeAdapter(TM_PeriodDuration.class),
 
     // Java types, primitive types and basic OGC types handling
+    @XmlJavaTypeAdapter(FeatureTypeAdapter.class),
+    @XmlJavaTypeAdapter(AttributeTypeAdapter.class),
     @XmlJavaTypeAdapter(StringAdapter.class),
     @XmlJavaTypeAdapter(CharSequenceAdapter.class),
     @XmlJavaTypeAdapter(InternationalStringAdapter.class)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
index 8fb3486..5bd306a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
@@ -103,7 +103,7 @@
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_Date.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(DQ_DataQuality.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(GO_Integer.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
index da2e79a..7709409 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
@@ -23,10 +23,9 @@
 import org.opengis.metadata.lineage.Lineage;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.quality.Element;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.apache.sis.metadata.iso.ISOMetadata;
-import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.xml.LegacyNamespaces;
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultScope.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultScope.java
index 5444cca..e24976e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultScope.java
@@ -40,7 +40,7 @@
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
- * @version 1.0
+ * @version 1.1
  * @since   0.3
  * @module
  *
@@ -79,7 +79,7 @@
      *
      * @see #castOrCopy(Scope)
      */
-    public DefaultScope(final Scope object) {
+    public DefaultScope(final org.opengis.metadata.maintenance.Scope object) {
         super(object);
     }
 
@@ -101,7 +101,7 @@
      * @return a SIS implementation containing the values of the given object (may be the
      *         given object itself), or {@code null} if the argument was null.
      */
-    public static DefaultScope castOrCopy(final Scope object) {
+    public static DefaultScope castOrCopy(final org.opengis.metadata.maintenance.Scope object) {
         if (object == null || object instanceof DefaultScope) {
             return (DefaultScope) object;
         }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/package-info.java
index 8fb66e9..f68c3e3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/package-info.java
@@ -141,7 +141,7 @@
     @XmlJavaTypeAdapter(MD_ContentInformation.class),
     @XmlJavaTypeAdapter(MD_Format.class),
     @XmlJavaTypeAdapter(MD_Identifier.class),
-    @XmlJavaTypeAdapter(MD_Scope.class),
+    @XmlJavaTypeAdapter(MD_Scope.Legacy.class),
     @XmlJavaTypeAdapter(MD_SpatialRepresentation.class),
     @XmlJavaTypeAdapter(MD_SpatialRepresentationTypeCode.class),
     @XmlJavaTypeAdapter(MX_DataFile.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
index ff09f09..583e43b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
@@ -75,7 +75,7 @@
     "checkPointAvailable",
     "checkPointDescription",
     "cornerPoints",
-    "centrePoint",
+    "centerPoint",
     "pointInPixel",
     "transformationDimensionDescription",
     "transformationDimensionMapping",
@@ -87,7 +87,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 6234748157247202686L;
+    private static final long serialVersionUID = -2924562334097446037L;
 
     /**
      * Mask for the {@code checkPointAvailable} boolean value.
@@ -115,7 +115,7 @@
      * and the grid coordinate of the cell halfway between opposite ends of the grid in the
      * spatial dimensions.
      */
-    private Point centrePoint;
+    private Point centerPoint;
 
     /**
      * Point in a pixel corresponding to the Earth location of the pixel.
@@ -157,7 +157,7 @@
         if (object != null) {
             checkPointDescription              = object.getCheckPointDescription();
             cornerPoints                       = copyList(object.getCornerPoints(), Point.class);
-            centrePoint                        = object.getCentrePoint();
+            centerPoint                        = object.getCenterPoint();
             pointInPixel                       = object.getPointInPixel();
             transformationDimensionDescription = object.getTransformationDimensionDescription();
             transformationDimensionMapping     = copyCollection(object.getTransformationDimensionMapping(), InternationalString.class);
@@ -294,22 +294,30 @@
      * and the grid coordinate of the cell halfway between opposite ends of the grid in the
      * spatial dimensions.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code getCentrePoint()} in GeoAPI 4.0
+     * for compliance with ISO 19115:2014.</div>
+     *
      * @return the center point, or {@code null}.
      */
     @Override
     @XmlElement(name = "centrePoint")
-    public Point getCentrePoint() {
-        return centrePoint;
+    public Point getCenterPoint() {
+        return centerPoint;
     }
 
     /**
      * Sets the center point.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method may be renamed {@code setCentrePoint(…)} in GeoAPI 4.0
+     * for compliance with ISO 19115:2014.</div>
+     *
      * @param  newValue  the new center point.
      */
-    public void setCentrePoint(final Point newValue) {
-        checkWritePermission(centrePoint);
-        centrePoint = newValue;
+    public void setCenterPoint(final Point newValue) {
+        checkWritePermission(centerPoint);
+        centerPoint = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
index 63a1590..13e06a9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
@@ -33,6 +33,10 @@
 import org.apache.sis.internal.metadata.Dependencies;
 import org.apache.sis.internal.util.Numerics;
 
+// Branch-dependent imports
+import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
+
 
 /**
  * The handler for metadata proxy that implement (indirectly) metadata interfaces like
@@ -128,7 +132,7 @@
      * @return the value to be returned from the public method invoked by the method.
      */
     @Override
-    public Object invoke(final Object proxy, final Method method, final Object[] args) {
+    public Object invoke(final Object proxy, Method method, final Object[] args) {
         final int n = (args != null) ? args.length : 0;
         switch (method.getName()) {
             case "toString": {
@@ -157,6 +161,8 @@
                  */
                 Object value;
                 try {
+                    method = supercede(method);
+                    if (method == null) return null;
                     value = fetchValue(source.getLookupInfo(method.getDeclaringClass()), method);
                 } catch (ReflectiveOperationException | SQLException | MetadataStoreException e) {
                     throw new BackingStoreException(error(method), e);
@@ -316,4 +322,25 @@
     public String toString() {
         return toString(getClass());
     }
+
+    /**
+     * If the given method is superceded by a new method, the new method.
+     * This is a hack for transition from legacy ISO type to newer type:
+     * {@code ResponsibleParty.getRole()} overriding {@code Responsibility.getRole()}
+     * confuses this {@code Dispatcher} class. We need the method in the base interface.
+     */
+    private static Method supercede(Method method) throws NoSuchMethodException {
+        if (method.getDeclaringClass() == ResponsibleParty.class) {
+            if ("getRole".equals(method.getName())) {
+                method = Responsibility.class.getMethod("getRole");
+            } else {
+                /*
+                 * `getIndividualName()`, `getOrganisationName()`, `getPositionName()` and
+                 * `getContactInfo()` have no direct equivalence in `Responsibility` class.
+                 */
+                return null;
+            }
+        }
+        return method;
+    }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
index 4f7a6f2..be47e90 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
@@ -23,7 +23,6 @@
 import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.ArgumentChecks;
@@ -31,6 +30,9 @@
 
 import static java.util.Collections.singleton;
 
+// Branch-dependent import
+import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+
 
 /**
  * A fallback providing hard-coded values of metadata entities.
@@ -214,8 +216,9 @@
         if (code                  != null) c.setIdentifiers(singleton(new DefaultIdentifier(codeSpace, code, version)));
         if (presentationForm      != null) c.setPresentationForms(singleton(presentationForm));
         if (citedResponsibleParty != null) {
-            c.setCitedResponsibleParties(singleton(new DefaultResponsibility(Role.PRINCIPAL_INVESTIGATOR, null,
-                    new DefaultOrganisation(citedResponsibleParty, null, null, null))));
+            final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.PRINCIPAL_INVESTIGATOR);
+            r.setParties(singleton(new DefaultOrganisation(citedResponsibleParty, null, null, null)));
+            c.setCitedResponsibleParties(singleton(r));
         }
         if (copyFrom != null) {
             c.setCitedResponsibleParties(createCitation(copyFrom).getCitedResponsibleParties());
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
index a877637..f16a26a 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.cat;
 
 import java.util.Arrays;
-import java.util.EnumSet;
 import java.util.Collection;
 import javax.xml.bind.JAXBException;
 import org.opengis.metadata.identification.TopicCategory;
@@ -72,7 +71,6 @@
          * Unmarshal the above XML and verify that we find all the topic categories.
          */
         final Collection<TopicCategory> unmarshalled = unmarshal(DefaultDataIdentification.class, expected).getTopicCategories();
-        assertInstanceOf("topicCategory", EnumSet.class, unmarshalled);
         assertSetEquals(topics, unmarshalled);
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/HashCodeTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/HashCodeTest.java
index 240dd3c..d526d0e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/HashCodeTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/HashCodeTest.java
@@ -22,14 +22,14 @@
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.Individual;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.acquisition.Instrument;
 import org.opengis.metadata.acquisition.Platform;
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.metadata.iso.acquisition.DefaultInstrument;
 import org.apache.sis.metadata.iso.acquisition.DefaultPlatform;
 import org.apache.sis.test.DependsOnMethod;
@@ -89,8 +89,9 @@
         final InternationalString   title    = new SimpleInternationalString("Some title");
         final InternationalString   person   = new SimpleInternationalString("Illustre inconnu");
         final DefaultIndividual     party    = new DefaultIndividual(person, null, null);
-        final DefaultResponsibility resp     = new DefaultResponsibility(Role.AUTHOR, null, party);
+        final DefaultResponsibleParty resp   = new DefaultResponsibleParty(Role.AUTHOR);
         final DefaultCitation       instance = new DefaultCitation(title);
+        resp.getParties().add(party);
         instance.getCitedResponsibleParties().add(resp);
         /*
          * Individual hash code is the sum of all its properties, none of them being a collection.
@@ -100,7 +101,7 @@
         /*
          * The +31 below come from java.util.List contract, since above Individual is a list member.
          */
-        expected += Responsibility.class.hashCode() + Role.AUTHOR.hashCode() + 31;
+        expected += ResponsibleParty.class.hashCode() + Role.AUTHOR.hashCode() + 31;
         assertEquals("Responsibility", Integer.valueOf(expected), hash(resp));
         /*
          * The +31 below come from java.util.List contract, since above Responsibility is a list member.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
index 99c4b83..1816da1 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
@@ -32,7 +32,7 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.content.AttributeGroup;
@@ -43,6 +43,7 @@
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.datum.GeodeticDatum;
@@ -178,10 +179,10 @@
             Citation.class, "getEdition",                 "edition",                 "edition",               "Edition",                    InternationalString.class,
             Citation.class, "getEditionDate",             "editionDate",             "editionDate",           "Edition date",               Date.class,
             Citation.class, "getIdentifiers",             "identifiers",             "identifier",            "Identifiers",                Identifier[].class,
-            Citation.class, "getCitedResponsibleParties", "citedResponsibleParties", "citedResponsibleParty", "Cited responsible parties",  Responsibility[].class,
+            Citation.class, "getCitedResponsibleParties", "citedResponsibleParties", "citedResponsibleParty", "Cited responsible parties",  ResponsibleParty[].class,
             Citation.class, "getPresentationForms",       "presentationForms",       "presentationForm",      "Presentation forms",         PresentationForm[].class,
             Citation.class, "getSeries",                  "series",                  "series",                "Series",                     Series.class,
-            Citation.class, "getOtherCitationDetails",    "otherCitationDetails",    "otherCitationDetails",  "Other citation details",     InternationalString[].class,
+            Citation.class, "getOtherCitationDetails",    "otherCitationDetails",    "otherCitationDetails",  "Other citation details",     InternationalString.class,
 //          Citation.class, "getCollectiveTitle",         "collectiveTitle",         "collectiveTitle",       "Collective title",           InternationalString.class,   -- deprecated as of ISO 19115:2014
             Citation.class, "getISBN",                    "ISBN",                    "ISBN",                  "ISBN",                       String.class,
             Citation.class, "getISSN",                    "ISSN",                    "ISSN",                  "ISSN",                       String.class,
@@ -206,9 +207,9 @@
             Identification.class, "getCitation",                   "citation",                   "citation",                  "Citation",                     Citation.class,
             Identification.class, "getAbstract",                   "abstract",                   "abstract",                  "Abstract",                     InternationalString.class,
             Identification.class, "getPurpose",                    "purpose",                    "purpose",                   "Purpose",                      InternationalString.class,
-            Identification.class, "getCredits",                    "credits",                    "credit",                    "Credits",                      InternationalString[].class,
+            Identification.class, "getCredits",                    "credits",                    "credit",                    "Credits",                      String[].class,
             Identification.class, "getStatus",                     "status",                     "status",                    "Status",                       Progress[].class,
-            Identification.class, "getPointOfContacts",            "pointOfContacts",            "pointOfContact",            "Point of contacts",            Responsibility[].class,
+            Identification.class, "getPointOfContacts",            "pointOfContacts",            "pointOfContact",            "Point of contacts",            ResponsibleParty[].class,
             Identification.class, "getSpatialRepresentationTypes", "spatialRepresentationTypes", "spatialRepresentationType", "Spatial representation types", SpatialRepresentationType[].class,
             Identification.class, "getSpatialResolutions",         "spatialResolutions",         "spatialResolution",         "Spatial resolutions",          Resolution[].class,
             Identification.class, "getTemporalResolutions",        "temporalResolutions",        "temporalResolution",        "Temporal resolutions",         Duration[].class,
@@ -240,10 +241,10 @@
         //……Declaring type……………………………Method……………………………………………JavaBeans……………………………UML identifier………………Sentence…………………………………Type…………………………………………………………
             GeographicCRS.class,    "getCoordinateSystem", "coordinateSystem", "coordinateSystem", "Coordinate system",  EllipsoidalCS.class,       // Covariant return type
             GeodeticCRS.class,      "getDatum",            "datum",            "datum",            "Datum",              GeodeticDatum.class,       // Covariant return type
-            IdentifiedObject.class, "getName",             "name",             "name",             "Name",               Identifier.class,
+            IdentifiedObject.class, "getName",             "name",             "name",             "Name",               ReferenceIdentifier.class,
             IdentifiedObject.class, "getAlias",            "alias",            "alias",            "Alias",              GenericName[].class,
             ReferenceSystem.class,  "getDomainOfValidity", "domainOfValidity", "domainOfValidity", "Domain of validity", Extent.class,
-            IdentifiedObject.class, "getIdentifiers",      "identifiers",      "identifier",       "Identifiers",        Identifier[].class,
+            IdentifiedObject.class, "getIdentifiers",      "identifiers",      "identifier",       "Identifiers",        ReferenceIdentifier[].class,
             IdentifiedObject.class, "getRemarks",          "remarks",          "remarks",          "Remarks",            InternationalString.class,
             ReferenceSystem.class,  "getScope",            "scope",            "SC_CRS.scope",     "Scope",              InternationalString.class);
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
index 4eaae22..5c96d80 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
@@ -18,8 +18,8 @@
 
 import java.util.Locale;
 import org.opengis.util.InternationalString;
-import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
+import org.opengis.metadata.Obligation;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.PresentationForm;
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
index 084cb33..cc05163 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
@@ -21,7 +21,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Collections;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.PresentationForm;
@@ -70,7 +69,7 @@
     static DefaultCitation metadataWithoutCollections() {
         final DefaultCitation citation = new DefaultCitation("Some title");
         citation.setEdition(new SimpleInternationalString("Some edition"));
-        citation.setOtherCitationDetails(Collections.singleton(new SimpleInternationalString("Some other details")));
+        citation.setOtherCitationDetails(new SimpleInternationalString("Some other details"));
         return citation;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
index 7163237..79db6a9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
@@ -22,14 +22,14 @@
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.Party;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.PresentationForm;
 import org.opengis.metadata.citation.Role;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultAddress;
 import org.apache.sis.metadata.iso.citation.DefaultContact;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
 import org.apache.sis.metadata.iso.citation.AbstractParty;
@@ -84,7 +84,8 @@
     static DefaultCitation metadataWithHierarchy() {
         final DefaultCitation citation = TreeNodeChildrenTest.metadataWithMultiOccurrences();
         AbstractParty party = new DefaultOrganisation("Some organisation", null, null, null);
-        DefaultResponsibility responsibility = new DefaultResponsibility(Role.DISTRIBUTOR, null, party);
+        DefaultResponsibleParty responsibility = new DefaultResponsibleParty(Role.DISTRIBUTOR);
+        responsibility.setParties(singleton(party));
         assertTrue(citation.getCitedResponsibleParties().add(responsibility));
 
         // Add a second responsible party with deeper hierarchy.
@@ -93,7 +94,8 @@
         address.setElectronicMailAddresses(singleton("Some email"));
         contact.setAddresses(singleton(address));
         party = new DefaultIndividual("Some person of contact", null, contact);
-        responsibility = new DefaultResponsibility(Role.POINT_OF_CONTACT, null, party);
+        responsibility = new DefaultResponsibleParty(Role.POINT_OF_CONTACT);
+        responsibility.setParties(singleton(party));
         assertTrue(citation.getCitedResponsibleParties().add(responsibility));
         return citation;
     }
@@ -177,7 +179,7 @@
      *
      * <p>If {@link #valuePolicy} is {@link ValueExistencePolicy#COMPACT}, then this method removes the elements at
      * indices 0, 6 and 10 (if {@code offset} = 0) or 1, 7 and 11 (if {@code offset} = 1) from the {@code expected}
-     * array before to perform the comparison.</p>
+     * array before to perform the comparison (note: actual indices vary according branches).</p>
      *
      * @param  offset    0 if compact mode excludes the parent, or 1 if compact mode exclude the first child.
      * @param  column    the column from which to get a value.
@@ -188,8 +190,8 @@
     private void assertCitationContentEquals(final int offset, final TableColumn<?> column, final Object... expected) {
         if (valuePolicy == ValueExistencePolicy.COMPACT) {
             assertEquals(19, expected.length);
-            System.arraycopy(expected, 12+offset, expected, 11+offset,  7-offset);    // Compact the "Individual" element.
-            System.arraycopy(expected,  8+offset, expected,  7+offset, 10-offset);    // Compact the "Organisation" element.
+            System.arraycopy(expected, 11+offset, expected, 10+offset,  8-offset);    // Compact the "Individual" element.
+            System.arraycopy(expected,  7+offset, expected,  6+offset, 11-offset);    // Compact the "Organisation" element.
             System.arraycopy(expected,  1+offset, expected,    offset, 16-offset);    // Compact the "Title" element.
             Arrays.fill(expected, 16, 19, null);
         }
@@ -209,16 +211,16 @@
               "Alternate title (2 of 2)",
               "Edition",
               "Cited responsible party (1 of 2)",
-                "Role",
-                "Organisation",                         // A Party subtype
+                "Organisation",
                   "Name",                               // In COMPACT mode, this value is associated to "Organisation" node.
-              "Cited responsible party (2 of 2)",
                 "Role",
-                "Individual",                           // A Party subtype
+              "Cited responsible party (2 of 2)",
+                "Individual",
                   "Name",                               // In COMPACT mode, this value is associated to "Individual" node.
                   "Contact info",
                     "Address",
                       "Electronic mail address",
+                "Role",
               "Presentation form (1 of 2)",
               "Presentation form (2 of 2)",
               "Other citation details");
@@ -240,16 +242,16 @@
               "alternateTitle",
               "edition",
               "citedResponsibleParty",
-                "role",
                 "party",
                   "name",                               // In COMPACT mode, this value is associated to "party" node.
-              "citedResponsibleParty",
                 "role",
+              "citedResponsibleParty",
                 "party",
                   "name",                               // In COMPACT mode, this value is associated to "party" node.
                   "contactInfo",
                     "address",
                       "electronicMailAddress",
+                "role",
               "presentationForm",
               "presentationForm",
               "otherCitationDetails");
@@ -263,6 +265,7 @@
     public void testGetIndex() {
         final Integer ZERO = 0;
         final Integer ONE  = 1;
+        skipCountCheck = true;                              // Because of the null value at the end of following array.
         assertCitationContentEquals(1, TableColumn.INDEX,
             null,           // CI_Citation
               null,         // title
@@ -270,19 +273,19 @@
               ONE,          // alternateTitle
               null,         // edition
               ZERO,         // citedResponsibleParty
-                null,       // role
                 ZERO,       // party (organisation)
                   null,     // name                         — in COMPACT mode, this value is associated to "party" node.
-              ONE,          // citedResponsibleParty
                 null,       // role
+              ONE,          // citedResponsibleParty
                 ZERO,       // party (individual)
                   null,     // name                         — in COMPACT mode, this value is associated to "party" node.
                   ZERO,     // contactInfo
                     ZERO,   // address
                       ZERO, // electronicMailAddress
+                null,       // role
               ZERO,         // presentationForm
               ONE,          // presentationForm
-              ZERO);        // otherCitationDetails
+              null);        // otherCitationDetails
     }
 
     /**
@@ -297,17 +300,17 @@
               InternationalString.class,
               InternationalString.class,
               InternationalString.class,
-              Responsibility.class,
-                Role.class,
+              ResponsibleParty.class,
                 Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
                   InternationalString.class,            // Name
-              Responsibility.class,
                 Role.class,
+              ResponsibleParty.class,
                 Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
                   InternationalString.class,            // Name
                   Contact.class,
                     Address.class,
                       String.class,
+                Role.class,
               PresentationForm.class,
               PresentationForm.class,
               InternationalString.class);
@@ -326,16 +329,16 @@
               "Second alternate title",
               "Some edition",
               null,                             // ResponsibleParty
-                Role.DISTRIBUTOR,
                 null,                           // Party (organisation)
                   "Some organisation",
+                Role.DISTRIBUTOR,
               null,                             // ResponsibleParty
-                Role.POINT_OF_CONTACT,
                 null,                           // Party (individual)
                   "Some person of contact",
                   null,                         // Contact
                     null,                       // Address
                       "Some email",
+                Role.POINT_OF_CONTACT,
               PresentationForm.MAP_DIGITAL,
               PresentationForm.MAP_HARDCOPY,
               "Some other details");
@@ -381,6 +384,12 @@
     }
 
     /**
+     * For disabling the check of child nodes count.
+     * This hack is specific to the branch using GeoAPI 3.0 (not needed on the branch using GeoAPI 4.0).
+     */
+    private boolean skipCountCheck;
+
+    /**
      * Compares the result of the given getter method invoked on the given node, then invoked
      * on all children of that given. In the particular case of the {@link TableColumn#NAME},
      * international strings are replaced by unlocalized strings before comparisons.
@@ -398,6 +407,7 @@
         if (valuePolicy == ValueExistencePolicy.COMPACT) {
             while (expected[count-1] == null) count--;
         }
+        if (skipCountCheck) return;
         assertEquals("Missing values in the tested metadata.", count,
                 assertColumnContentEquals(node, column, expected, 0));
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
index 9d8c298..9571ad9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
@@ -26,7 +26,7 @@
 import org.apache.sis.metadata.iso.content.DefaultImageDescription;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultCitationTest;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
 import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.metadata.iso.lineage.DefaultProcessing;
@@ -87,10 +87,9 @@
             "Citation……………………………………………………………………………… Undercurrent\n" +
             "  ├─Alternate title………………………………………………… Andākarento\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Role…………………………………………………………………… Author\n" +
-            "  │   └─Individual…………………………………………………… Testsuya Toyoda\n" +
+            "  │   ├─Individual…………………………………………………… Testsuya Toyoda\n" +
+            "  │   └─Role…………………………………………………………………… Author\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Role…………………………………………………………………… Editor\n" +
             "  │   ├─Extent……………………………………………………………… World\n" +
             "  │   │   └─Geographic element\n" +
             "  │   │       ├─West bound longitude…… 180°W\n" +
@@ -98,7 +97,8 @@
             "  │   │       ├─South bound latitude…… 90°S\n" +
             "  │   │       ├─North bound latitude…… 90°N\n" +
             "  │   │       └─Extent type code……………… True\n" +
-            "  │   └─Organisation……………………………………………… Kōdansha\n" +
+            "  │   ├─Organisation……………………………………………… Kōdansha\n" +
+            "  │   └─Role…………………………………………………………………… Editor\n" +
             "  ├─Presentation form (1 of 2)…………………… Document digital\n" +
             "  ├─Presentation form (2 of 2)…………………… Document hardcopy\n" +
             "  └─ISBN……………………………………………………………………………… 9782505004509\n", text);
@@ -114,7 +114,7 @@
         final DefaultCitation untitled = new DefaultCitation();
         titled  .setPresentationForms(singleton(PresentationForm.DOCUMENT_HARDCOPY));
         coded   .setPresentationForms(singleton(PresentationForm.IMAGE_HARDCOPY));
-        untitled.setCitedResponsibleParties(singleton(new DefaultResponsibility(Role.AUTHOR, null, null)));
+        untitled.setCitedResponsibleParties(singleton(new DefaultResponsibleParty(Role.AUTHOR)));
         final DefaultProcessing processing = new DefaultProcessing();
         processing.setDocumentations(asList(titled, coded, untitled));
         final String text = format.format(processing.asTreeTable());
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
index ba323ea..388d812 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
@@ -60,14 +60,14 @@
             "  ├─Alternate title (2 of 2)…………………………………………… Second alternate title\n" +
             "  ├─Edition………………………………………………………………………………………… Some edition\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Role……………………………………………………………………………………… Distributor\n" +
-            "  │   └─Organisation………………………………………………………………… Some organisation\n" +
+            "  │   ├─Organisation………………………………………………………………… Some organisation\n" +
+            "  │   └─Role……………………………………………………………………………………… Distributor\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Role……………………………………………………………………………………… Point of contact\n" +
-            "  │   └─Individual……………………………………………………………………… Some person of contact\n" +
-            "  │       └─Contact info\n" +
-            "  │           └─Address\n" +
-            "  │               └─Electronic mail address…… Some email\n" +
+            "  │   ├─Individual……………………………………………………………………… Some person of contact\n" +
+            "  │   │   └─Contact info\n" +
+            "  │   │       └─Address\n" +
+            "  │   │           └─Electronic mail address…… Some email\n" +
+            "  │   └─Role……………………………………………………………………………………… Point of contact\n" +
             "  ├─Presentation form (1 of 2)……………………………………… Map digital\n" +
             "  ├─Presentation form (2 of 2)……………………………………… Map hardcopy\n" +
             "  └─Other citation details………………………………………………… Some other details\n";
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
index 3614969..ac76716 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
@@ -24,7 +24,7 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.metadata.extent.GeographicDescription;
@@ -70,7 +70,7 @@
             new SimpleEntry<>("edition",               InternationalString.class),
             new SimpleEntry<>("editionDate",           Date.class),
             new SimpleEntry<>("identifier",            Identifier.class),
-            new SimpleEntry<>("citedResponsibleParty", Responsibility.class),
+            new SimpleEntry<>("citedResponsibleParty", ResponsibleParty.class),
             new SimpleEntry<>("presentationForm",      PresentationForm.class),
             new SimpleEntry<>("series",                Series.class),
             new SimpleEntry<>("otherCitationDetails",  InternationalString.class),
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
index a5d58b5..d51cbd2 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
@@ -24,7 +24,7 @@
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -68,7 +68,7 @@
     /**
      * The author of the metadata instance created by {@link #createCitation()}.
      */
-    private DefaultResponsibility author;
+    private DefaultResponsibleParty author;
 
     /**
      * Creates the metadata instance to be used for testing purpose.
@@ -91,7 +91,7 @@
      */
     private Map<String,Object> createCitation() {
         title    = new SimpleInternationalString("Undercurrent");
-        author   = new DefaultResponsibility();
+        author   = new DefaultResponsibleParty();
         citation = new DefaultCitation(title);
         author.setParties(singleton(new DefaultIndividual("Testsuya Toyoda", null, null)));
         citation.setCitedResponsibleParties(singleton(author));
@@ -172,7 +172,6 @@
             new SimpleEntry<>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
-            new SimpleEntry<>("otherCitationDetails",    emptyList()),
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("onlineResources",         emptyList()),
             new SimpleEntry<>("graphics",                emptyList())
@@ -203,7 +202,6 @@
             new SimpleEntry<>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
-            new SimpleEntry<>("otherCitationDetails",    emptyList()),
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("onlineResources",         emptyList()),
             new SimpleEntry<>("graphics",                emptyList())
@@ -234,7 +232,7 @@
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
             new SimpleEntry<>("series",                  null),
-            new SimpleEntry<>("otherCitationDetails",    emptyList()),
+            new SimpleEntry<>("otherCitationDetails",    null),
 //          new SimpleEntry<>("collectiveTitle",         null),  -- deprecated as of ISO 19115:2014.
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("ISSN",                    null),
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
index b8ea6f0..464cdf2a 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
@@ -106,7 +106,7 @@
             org.opengis.metadata.content.FeatureCatalogueDescription.class,
             org.opengis.metadata.content.ImageDescription.class,
             org.opengis.metadata.content.ImagingCondition.class,
-            org.opengis.metadata.content.PolarisationOrientation.class,
+            org.opengis.metadata.content.PolarizationOrientation.class,
             org.opengis.metadata.content.RangeDimension.class,
             org.opengis.metadata.content.RangeElementDescription.class,
             org.opengis.metadata.content.SampleDimension.class,
@@ -118,7 +118,7 @@
             org.opengis.metadata.distribution.Format.class,
             org.opengis.metadata.distribution.Medium.class,
             org.opengis.metadata.distribution.MediumFormat.class,
-            org.apache.sis.internal.metadata.legacy.MediumName.class,
+            org.opengis.metadata.distribution.MediumName.class,
             org.opengis.metadata.distribution.StandardOrderProcess.class,
             org.opengis.metadata.extent.BoundingPolygon.class,
             org.opengis.metadata.extent.Extent.class,
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java
deleted file mode 100644
index 2b11069..0000000
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.metadata.iso;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.logging.Filter;
-import java.util.logging.LogRecord;
-import java.util.MissingResourceException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.JAXBException;
-import org.opengis.annotation.Obligation;
-import org.opengis.util.RecordType;
-import org.opengis.metadata.Datatype;
-import org.opengis.metadata.citation.*;
-import org.opengis.metadata.constraint.*;
-import org.opengis.metadata.content.*;
-import org.opengis.metadata.extent.*;
-import org.opengis.metadata.identification.*;
-import org.opengis.metadata.maintenance.*;
-import org.opengis.metadata.spatial.*;
-import org.opengis.geometry.primitive.Point;
-import org.apache.sis.metadata.iso.citation.*;
-import org.apache.sis.metadata.iso.constraint.*;
-import org.apache.sis.metadata.iso.content.*;
-import org.apache.sis.metadata.iso.distribution.*;
-import org.apache.sis.metadata.iso.extent.*;
-import org.apache.sis.metadata.iso.identification.*;
-import org.apache.sis.metadata.iso.maintenance.*;
-import org.apache.sis.metadata.iso.spatial.*;
-import org.apache.sis.util.iso.DefaultRecordSchema;
-import org.apache.sis.util.SimpleInternationalString;
-import org.apache.sis.util.DefaultInternationalString;
-import org.apache.sis.measure.Units;
-import org.apache.sis.xml.XML;
-import org.apache.sis.xml.NilReason;
-import org.apache.sis.xml.MarshallerPool;
-import org.apache.sis.xml.IdentifierSpace;
-import org.apache.sis.internal.jaxb.gcx.Anchor;
-import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
-import org.apache.sis.metadata.xml.TestUsingFile;
-import org.apache.sis.util.iso.Names;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-
-/**
- * Simple test cases for marshalling a {@link DefaultMetadata} object to an XML file.
- * This class is used to test the ISO 19115-3 metadata standard implementation.
- *
- * @author  Cullen Rombach (Image Matters)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- *
- * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
- *
- * @since 1.0
- * @module
- */
-public final class MarshallingTest extends TestUsingFile implements Filter {
-    /**
-     * The marshaller used to handle marshalling the created DefaultMetadata object.
-     */
-    private final Marshaller marshaller;
-
-    /**
-     * The pool from which the marshaller is pulled.
-     */
-    private final MarshallerPool pool;
-
-    /**
-     * The output to which the metadata object will be marshalled.
-     */
-    private final StringWriter output;
-
-    /**
-     * {@code true} if marshalling legacy XML instead of latest schema.
-     */
-    private boolean legacyXML;
-
-    /**
-     * Initializes a new test case.
-     *
-     * @throws JAXBException if an error occurred while preparing the marshaller.
-     */
-    @SuppressWarnings("ThisEscapedInObjectConstruction")
-    public MarshallingTest() throws JAXBException {
-        output     = new StringWriter();
-        pool       = getMarshallerPool();
-        marshaller = pool.acquireMarshaller();
-        marshaller.setProperty(XML.WARNING_FILTER, this);
-    }
-
-    /**
-     * Creates a metadata object to marshal.
-     */
-    @SuppressWarnings("deprecation")
-    private static DefaultMetadata metadata() throws URISyntaxException {
-        /*
-         * Metadata
-         *   ├─Metadata identifier…… a-metadata-identifier
-         *   │   └─Code space………………… md.id.ns
-         *   ├─Parent metadata……………… A parent metadata
-         *   │   └─Identifier………………… a-parent-identifier
-         *   │       └─Code space……… pmd.id.ns
-         *   ├─Language (1 de 2)………… English
-         *   ├─Language (2 de 2)………… French (Canada)
-         *   ├─Character set…………………… ISO-8859-1
-         *   └─Metadata scope
-         *       ├─Resource scope……… Dataset
-         *       └─Name………………………………… Metadata for an imaginary data set
-         *
-         * Some code are indented for readability and more local variable scopes.
-         */
-        final DefaultMetadata md = new DefaultMetadata();
-        {
-            // Metadata identifier
-            final DefaultIdentifier id = new DefaultIdentifier("a-metadata-identifier");
-            id.setCodeSpace("md.id.ns");
-            md.setMetadataIdentifier(id);
-        }
-        // Languages — one language only, and one (country, language) tuple.
-        final Collection<Locale> languages = Arrays.asList(Locale.ENGLISH, Locale.CANADA_FRENCH);
-        md.setLanguages(languages);
-
-        // Character Sets (character encoding)
-        final Collection<Charset> charSets = Collections.singleton(StandardCharsets.ISO_8859_1);
-        md.setCharacterSets(charSets);
-        {
-            // Parent metadata
-            final DefaultCitation parent = new DefaultCitation("A parent metadata");
-            final DefaultIdentifier parentId = new DefaultIdentifier("a-parent-identifier");
-            parentId.setCodeSpace("pmd.id.ns");
-            parent.getIdentifiers().add(parentId);
-            md.setParentMetadata(parent);
-        }
-        // mdb:metadataScope (hierarchyLevel and hierarchyLevelName in legacy ISO 19115:2003 model)
-        md.getMetadataScopes().add(new DefaultMetadataScope(ScopeCode.DATASET, "Metadata for an imaginary data set"));
-        final DefaultOnlineResource onlineResource;
-        {
-            /*
-             * Contact information for the parties.
-             *
-             * Organisation………………………………………………………………… Plato Republic
-             *   ├─Contact info
-             *   │   ├─Phone (1 de 2)
-             *   │   │   ├─Number………………………………………………… 555-444-3333
-             *   │   │   └─Number type…………………………………… Voice
-             *   │   ├─Phone (2 de 2)
-             *   │   │   ├─Number………………………………………………… 555-555-5555
-             *   │   │   └─Number type…………………………………… Facsimile
-             *   │   ├─Address
-             *   │   │   ├─Delivery point…………………………… 123 Main Street
-             *   │   │   ├─City……………………………………………………… Metropolis city
-             *   │   │   ├─Administrative area……………… Utopia province
-             *   │   │   ├─Postal code…………………………………… A1A 2C2
-             *   │   │   ├─Country……………………………………………… Atlantis island
-             *   │   │   └─Electronic mail address…… test@example.com
-             *   │   ├─Online resource
-             *   │   │   ├─Linkage……………………………………………… http://example.com
-             *   │   │   ├─Protocol…………………………………………… Submarine HTTP
-             *   │   │   ├─Application profile……………… Imaginary work
-             *   │   │   ├─Name……………………………………………………… Timaeus & Critias
-             *   │   │   ├─Description…………………………………… A dialog between philosophers.
-             *   │   │   └─Function…………………………………………… Search
-             *   │   ├─Hours of service………………………………… Weekdays 9:00 AM - 5:00 PM
-             *   │   ├─Contact instructions……………………… Through thought
-             *   │   └─Contact type…………………………………………… Virtual
-             *   └─Individual…………………………………………………………… Socrates
-             *       └─Position name………………………………………… Philosopher
-             */
-            final DefaultContact contact = new DefaultContact();
-            contact.setPhones(Arrays.asList(new DefaultTelephone("555-444-3333", TelephoneType.VOICE),
-                                            new DefaultTelephone("555-555-5555", TelephoneType.FACSIMILE)));
-            {
-                {
-                    // Address information
-                    final DefaultAddress address = new DefaultAddress();
-                    address.setDeliveryPoints(Collections.singleton(new SimpleInternationalString("123 Main Street")));
-                    address.getElectronicMailAddresses().add("test@example.com");
-                    address.setCity(new SimpleInternationalString("Metropolis city"));
-                    address.setAdministrativeArea(new SimpleInternationalString("Utopia province"));
-                    address.setPostalCode("A1A 2C2");
-                    address.setCountry(new SimpleInternationalString("Atlantis island"));
-                    contact.getAddresses().add(address);
-                }
-                // Online resources
-                final DefaultInternationalString description = new DefaultInternationalString();
-                description.add(Locale.ENGLISH, "A dialog between philosophers.");
-                description.add(Locale.FRENCH,  "Un dialogue entre philosophes.");
-                onlineResource = new DefaultOnlineResource(new URI("http://example.com"));
-                onlineResource.setName(new SimpleInternationalString("Timaeus & Critias"));
-                onlineResource.setDescription(description);
-                onlineResource.setProtocol("Submarine HTTP");
-                onlineResource.setApplicationProfile("Imaginary work");
-                onlineResource.setFunction(OnLineFunction.SEARCH);
-                onlineResource.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "timaeus");    // For enabling references
-                contact.getOnlineResources().add(onlineResource);
-                contact.setHoursOfService(Collections.singleton(new SimpleInternationalString("Weekdays 9:00 AM - 5:00 PM")));
-                contact.setContactInstructions(new SimpleInternationalString("Through thought"));
-                contact.setContactType(new SimpleInternationalString("Virtual"));
-                contact.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "thought");           // For enabling references
-            }
-            // Create some individuals
-            final DefaultIndividual individual  = new DefaultIndividual("Socrates", "Philosopher", null);
-            final DefaultIndividual individual2 = new DefaultIndividual("Hermocrates", "Politician", contact);
-            final DefaultOrganisation org = new DefaultOrganisation("Plato Republic", null, individual, contact);
-            md.setContacts(Arrays.asList(new DefaultResponsibility(Role.POINT_OF_CONTACT, null, org),
-                                         new DefaultResponsibility(Role.POINT_OF_CONTACT, null, individual2)));
-        }
-        // Date info (date stamp in legacy ISO 19115:2003 model)
-        final Collection<CitationDate> dateInfo = Collections.singleton(new DefaultCitationDate(new Date(1260961229580L), DateType.CREATION));
-        md.setDateInfo(dateInfo);
-        {
-            // Metadata standard
-            final DefaultCitation standard = new DefaultCitation("ISO 19115-1");
-            standard.setEdition(new SimpleInternationalString("2014"));
-            md.getMetadataStandards().add(standard);
-        }
-        {
-            /*
-             * Spatial representation info : Georectified
-             *   ├─Number of dimensions………………………………………………… 2
-             *   ├─Axis dimension properties (1 de 2)…………… Row
-             *   │   ├─Dimension size……………………………………………………… 7 777
-             *   │   └─Resolution………………………………………………………………… 10
-             *   ├─Axis dimension properties (2 de 2)…………… Column
-             *   │   ├─Dimension size……………………………………………………… 2 233
-             *   │   └─Resolution………………………………………………………………… 5
-             *   ├─Cell geometry…………………………………………………………………… Area
-             *   ├─Transformation parameter availability…… false
-             *   ├─Check point availability……………………………………… false
-             *   └─Point in pixel………………………………………………………………… Upper right
-             */
-            final DefaultGeorectified georectified = new DefaultGeorectified();
-            georectified.setNumberOfDimensions(2);
-            final DefaultDimension rows = new DefaultDimension(DimensionNameType.ROW,    7777);
-            final DefaultDimension cols = new DefaultDimension(DimensionNameType.COLUMN, 2233);
-            rows.setResolution(10.0);
-            cols.setResolution( 5.0);
-            georectified.setAxisDimensionProperties(Arrays.asList(rows, cols));
-            georectified.setCellGeometry(CellGeometry.AREA);
-            georectified.setPointInPixel(PixelOrientation.UPPER_RIGHT);
-            georectified.getCornerPoints().add(NilReason.MISSING.createNilObject(Point.class));
-            md.getSpatialRepresentationInfo().add(georectified);
-        }
-        {
-            // Reference System Information
-            final ReferenceSystemMetadata refSystem = new ReferenceSystemMetadata();
-            final DefaultCitation cit = new DefaultCitation("Atlantis grid");
-            cit.setDates(dateInfo);
-            {
-                //  Responsibilities
-                final DefaultOrganisation org = new DefaultOrganisation();
-                org.setName(new SimpleInternationalString("Atlantis national mapping agency"));
-                cit.getCitedResponsibleParties().add(new DefaultResponsibility(Role.PUBLISHER, null, org));
-            }
-            // Identifier
-            final DefaultIdentifier id = new DefaultIdentifier("AG9000");
-            id.setAuthority(cit);
-            id.setCodeSpace("rs.id.ns");
-            id.setVersion("1.0");
-            id.setDescription(new SimpleInternationalString("An imaginary reference system."));
-            refSystem.setName(id);
-            md.getReferenceSystemInfo().add(refSystem);
-        }
-        {
-            /*
-             * Extended element information…… ExtendedElementName
-             *   ├─Parent entity………………………………… VirtualObject
-             *   ├─Definition………………………………………… An extended element not included in the standard.
-             *   ├─Obligation………………………………………… Conditional
-             *   ├─Condition…………………………………………… Presents in “Imaginary work” profile.
-             *   ├─Data type…………………………………………… Meta class
-             *   ├─Maximum occurrence…………………… 3
-             *   ├─Domain value…………………………………… Alpha, beta or gamma.
-             *   ├─Rule………………………………………………………… Element exists in cited resource.
-             *   └─Rationale…………………………………………… For testing extended elements.
-             */
-            final DefaultMetadataExtensionInformation extension = new DefaultMetadataExtensionInformation();
-            extension.setExtensionOnLineResource(onlineResource);
-            final DefaultExtendedElementInformation elementInfo = new DefaultExtendedElementInformation();
-            elementInfo.setName("ExtendedElementName");
-            elementInfo.setDefinition(new SimpleInternationalString("An extended element not included in the standard."));
-            elementInfo.setObligation(Obligation.CONDITIONAL);
-            elementInfo.setCondition(new SimpleInternationalString("Presents in “Imaginary work” profile."));
-            elementInfo.setDataType(Datatype.META_CLASS);
-            elementInfo.setMaximumOccurrence(3);
-            elementInfo.setDomainValue(new SimpleInternationalString("Alpha, beta or gamma."));
-            elementInfo.setShortName("ExtEltName");
-            elementInfo.setDomainCode(1234);
-            elementInfo.setParentEntity(Collections.singleton("VirtualObject"));
-            elementInfo.setRule(new SimpleInternationalString("Element exists in cited resource."));
-            elementInfo.setRationale(new SimpleInternationalString("For testing extended elements."));
-            elementInfo.getSources().add(NilReason.valueOf("other:test").createNilObject(Responsibility.class));
-            extension.getExtendedElementInformation().add(elementInfo);
-            md.getMetadataExtensionInfo().add(extension);
-        }
-        /*
-         * Data identification info
-         *   ├─Abstract………………… Méta-données pour une carte imaginaire.
-         *   └─Purpose…………………… For XML (un)marshalling tests.
-         */
-        final DefaultDataIdentification dataId = new DefaultDataIdentification();
-        {
-            final DefaultInternationalString description = new DefaultInternationalString();
-            description.add(Locale.ENGLISH, "Metadata for an imaginary map.");
-            description.add(Locale.FRENCH,  "Méta-données pour une carte imaginaire.");
-            dataId.setAbstract(description);
-            dataId.setPurpose(new SimpleInternationalString("For XML (un)marshalling tests."));
-        }
-        final Collection<Extent> extents;
-        {
-            /*
-             * Extent……………………………………………………………… Azores
-             *   ├─Geographic element
-             *   │   ├─West bound longitude…… 24°30′W
-             *   │   ├─East bound longitude…… 32°W
-             *   │   ├─South bound latitude…… 36°45′N
-             *   │   ├─North bound latitude…… 40°N
-             *   │   └─Extent type code……………… true
-             *   └─Temporal element
-             */
-            final DefaultExtent extent = new DefaultExtent();
-            extent.setDescription(new SimpleInternationalString("Azores"));
-            {
-                final DefaultGeographicBoundingBox bbox = new DefaultGeographicBoundingBox();
-                bbox.setInclusion(true);
-                bbox.setNorthBoundLatitude( 40.00);
-                bbox.setEastBoundLongitude(-32.00);
-                bbox.setSouthBoundLatitude( 36.75);
-                bbox.setWestBoundLongitude(-24.50);
-                extent.getGeographicElements().add(bbox);
-            }
-            final DefaultTemporalExtent temporal = new DefaultTemporalExtent();
-            extent.getTemporalElements().add(temporal);
-            extent.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "azores");     // For enabling references
-            extents = Collections.singleton(extent);
-            dataId.setExtents(extents);
-        }
-        final Collection<Constraints> resourceConstraints;
-        {
-            /*
-             * Constraints
-             *   ├─Use limitation…………………………………… Not for navigation.
-             *   ├─Constraint application scope
-             *   │   └─Level………………………………………………… Document
-             *   ├─Graphic
-             *   │   ├─File name……………………………………… ocean.png
-             *   │   ├─File description…………………… Somewhere in the Atlantic ocean
-             *   │   ├─File type……………………………………… PNG image
-             *   │   ├─Linkage
-             *   │   └─Image constraints
-             *   └─Releasability
-             *       └─Statement……………………………………… Public domain
-             */
-            final DefaultConstraints constraint = new DefaultConstraints();
-            final DefaultBrowseGraphic graphic = new DefaultBrowseGraphic(new URI("ocean.png"));
-            graphic.setFileDescription(new SimpleInternationalString("Somewhere in the Atlantic ocean"));
-            graphic.setFileType("PNG image");
-            graphic.getImageConstraints().add(new DefaultConstraints());
-            graphic.getLinkages().add(new DefaultOnlineResource());
-            constraint.getGraphics().add(graphic);
-            constraint.setUseLimitations(Collections.singleton(new SimpleInternationalString("Not for navigation.")));
-
-            // Releasability
-            final DefaultReleasability releasability = new DefaultReleasability();
-            releasability.setStatement(new SimpleInternationalString("Public domain"));
-            constraint.setReleasability(releasability);
-            constraint.setConstraintApplicationScope(new DefaultScope(ScopeCode.DOCUMENT));
-            constraint.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "public");         // For enabling references
-            resourceConstraints = Collections.singleton(constraint);
-            dataId.setResourceConstraints(resourceConstraints);
-        }
-        dataId.getSpatialRepresentationTypes().add(SpatialRepresentationType.GRID);
-        {
-            // Spatial resolution
-            final DefaultResolution resolution = new DefaultResolution();
-            resolution.setDistance(56777.0);
-            dataId.getSpatialResolutions().add(resolution);
-        }
-        dataId.setTopicCategories(Arrays.asList(TopicCategory.OCEANS, TopicCategory.SOCIETY));
-        dataId.getStatus().add(Progress.HISTORICAL_ARCHIVE);
-        /*
-         * Citation………………………………………………………… A lost island
-         *   ├─Alternate title (1 de 2)…… Island lost again
-         *   ├─Alternate title (2 de 2)…… Map example
-         *   ├─Date………………………………………………………… 2018-04-09 00:00:00
-         *   │   └─Date type………………………………… Création
-         *   ├─Edition………………………………………………… First edition
-         *   └─Edition date…………………………………… 2018-04-10 00:00:00
-         */
-        final DefaultCitation cit = new DefaultCitation();
-        cit.setTitle(new SimpleInternationalString("A lost island"));
-        cit.setEdition(new SimpleInternationalString("First edition"));
-        cit.setEditionDate(new Date(1523311200000L));
-        cit.setCollectiveTitle(new SimpleInternationalString("Popular legends"));
-        cit.setAlternateTitles(Arrays.asList(new SimpleInternationalString("Island lost again"),
-                                             new Anchor(new URI("http://map-example.com"), "Map example")));
-        cit.getDates().add(new DefaultCitationDate(new Date(1523224800000L), DateType.CREATION));
-        cit.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "lost-island");
-        dataId.setCitation(cit);
-        dataId.setTemporalResolutions(Collections.emptySet());          // TODO: need a more complete sis-temporal.
-        final Collection<MaintenanceInformation> resourceMaintenances;
-        {
-            /*
-             * Maintenance information
-             *   ├─Maintenance and update frequency…… Not planned
-             *   ├─Maintenance date……………………………………………… 3000-01-01 00:00:00
-             *   │   └─Date type……………………………………………………… Révision
-             *   └─Maintenance scope
-             *       ├─Level………………………………………………………………… Model
-             *       └─Level description
-             *           └─Dataset………………………………………………… Imaginary map
-             */
-            DefaultMaintenanceInformation maintenanceInfo = new DefaultMaintenanceInformation();
-            maintenanceInfo.setMaintenanceAndUpdateFrequency(MaintenanceFrequency.NOT_PLANNED);
-            maintenanceInfo.getMaintenanceDates().add(new DefaultCitationDate(new Date(32503676400000L), DateType.REVISION));
-            final DefaultScope maintenanceScope = new DefaultScope();
-            maintenanceScope.setLevel(ScopeCode.MODEL);
-            {
-                // Scope level descriptions
-                final DefaultScopeDescription scopeDescription = new DefaultScopeDescription();
-                scopeDescription.setDataset("Imaginary map");
-                maintenanceScope.getLevelDescription().add(scopeDescription);
-            }
-            maintenanceInfo.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "not-planned");
-            maintenanceInfo.getMaintenanceScopes().add(maintenanceScope);
-            resourceMaintenances = Collections.singleton(maintenanceInfo);
-            dataId.setResourceMaintenances(resourceMaintenances);
-        }
-        {
-            /*
-             * Format
-             *   ├─Format specification citation…… Portable Network Graphics
-             *   │   ├─Alternate title……………………………… PNG
-             *   │   └─Edition…………………………………………………… November 2003
-             *   ├─Amendment number……………………………………… Second edition
-             *   └─File decompression technique……… L77 / Huffman coding
-             */
-            final DefaultFormat resourceFormat = new DefaultFormat();
-            resourceFormat.setName(new SimpleInternationalString("PNG"));
-            resourceFormat.setSpecification(new SimpleInternationalString("Portable Network Graphics"));
-            resourceFormat.setAmendmentNumber(new SimpleInternationalString("Second edition"));
-            resourceFormat.setVersion(new SimpleInternationalString("November 2003"));
-            resourceFormat.setFileDecompressionTechnique(new SimpleInternationalString("L77 / Huffman coding"));
-            dataId.getResourceFormats().add(resourceFormat);
-        }
-        final Collection<Keywords> descriptiveKeywords;
-        {
-            /*
-             * Keywords
-             *   ├─Thesaurus name………… Plato's dialogues
-             *   ├─Keyword class…………… Greek elements
-             *   ├─Keyword (1 de 2)…… Water
-             *   ├─Keyword (2 de 2)…… Aether
-             *   └─Type…………………………………… Theme
-             */
-            final DefaultKeywords keywords = new DefaultKeywords();
-            keywords.setType(KeywordType.THEME);
-            keywords.setThesaurusName(new DefaultCitation("Plato's dialogues"));
-            final DefaultKeywordClass keywordClass = new DefaultKeywordClass();
-            keywordClass.setClassName(new SimpleInternationalString("Greek elements"));
-            keywords.setKeywordClass(keywordClass);
-            keywords.setKeywords(Arrays.asList(new SimpleInternationalString("Water"),
-                                               new SimpleInternationalString("Aether")));
-            keywords.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "greek-elements");
-            descriptiveKeywords = Collections.singleton(keywords);
-            dataId.setDescriptiveKeywords(descriptiveKeywords);
-        }
-        {
-            /*
-             * Usage………………………………………………………………………… For testing purpose only.
-             *   ├─Usage date time…………………………………… 2018-04-10 14:00:00
-             *   ├─User determined limitations…… Not to be used outside MarshallingTest.java test file.
-             *   └─Response……………………………………………………… Random elements
-             */
-            final DefaultUsage usage = new DefaultUsage();
-            usage.setSpecificUsage(new SimpleInternationalString("For testing purpose only."));
-            usage.setUsageDate(new Date(1523361600000L));
-            usage.setResponses(Collections.singleton(new SimpleInternationalString("Random elements")));
-            usage.setUserDeterminedLimitations(new SimpleInternationalString("Not to be used outside MarshallingTest.java test file."));
-            dataId.getResourceSpecificUsages().add(usage);
-        }
-        final Collection<AssociatedResource> associatedResources;
-        {
-            // Associated resources (AggregationInfo in 19139)
-            final DefaultAssociatedResource associatedResource = new DefaultAssociatedResource();
-            associatedResource.setAssociationType(AssociationType.DEPENDENCY);
-            associatedResource.setInitiativeType(InitiativeType.EXPERIMENT);
-            associatedResource.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "dependency");
-            associatedResources = Collections.singleton(associatedResource);
-            dataId.setAssociatedResources(associatedResources);
-        }
-        dataId.setLanguages(languages);     // Locales (ISO 19115:2014) a.k.a Languages and CharacterSets (ISO 19115:2003)
-        dataId.setCharacterSets(charSets);
-        dataId.setEnvironmentDescription (new SimpleInternationalString("High humidity."));
-        dataId.setSupplementalInformation(new SimpleInternationalString("High water pressure."));
-        {
-            // Service identification info
-            final DefaultServiceIdentification serviceId = new DefaultServiceIdentification();
-            serviceId.setCitation(cit);
-            serviceId.setAbstract(new SimpleInternationalString("An inspiration for story tellers."));
-            serviceId.setExtents(extents);
-            serviceId.setResourceMaintenances(resourceMaintenances);
-            serviceId.setDescriptiveKeywords(descriptiveKeywords);
-            serviceId.setResourceConstraints(resourceConstraints);
-            serviceId.setAssociatedResources(associatedResources);
-            serviceId.setServiceTypeVersions(Collections.singleton("Version 1000+"));
-            // TODO: Coupled resources
-            final DefaultCoupledResource coupledResource = new DefaultCoupledResource();
-            serviceId.getCoupledResources().add(coupledResource);
-            serviceId.setCouplingType(CouplingType.LOOSE);
-            final DefaultOperationMetadata operationMetadata = new DefaultOperationMetadata();
-            {
-                operationMetadata.setOperationName("Authoring");
-                operationMetadata.setOperationDescription(new SimpleInternationalString("Write a book."));
-                operationMetadata.setInvocationName(new SimpleInternationalString("someMethodName"));
-                operationMetadata.getDistributedComputingPlatforms().add(DistributedComputingPlatform.JAVA);
-            }
-            serviceId.getContainsOperations().add(operationMetadata);
-            serviceId.getOperatesOn().add(dataId);
-            md.setIdentificationInfo(Arrays.asList(dataId, serviceId));
-        }
-        {
-            // Content info
-            final DefaultCoverageDescription coverageDescription;
-            {
-                coverageDescription = new DefaultCoverageDescription();
-                // Attribute description
-                final DefaultRecordSchema schema = new DefaultRecordSchema(null, null, "IslandFeatures");
-                final Map<CharSequence,Class<?>> members = new LinkedHashMap<>();
-                members.put("city",      String.class);
-                members.put("latitude",  Double.class);
-                members.put("longitude", Double.class);
-                final RecordType recordType = schema.createRecordType("SettledArea", members);
-                coverageDescription.setAttributeDescription(recordType);
-                {
-                    /*
-                     * Attribute group
-                     *   ├─Content type…………………… Auxilliary information
-                     *   ├─Attribute (1 de 2)…… 42
-                     *   │   ├─Description…………… Population density
-                     *   │   └─Name
-                     *   └─Attribute (2 de 2)
-                     *       ├─Description…………… Temperature
-                     *       ├─Max value………………… 22,22
-                     *       ├─Min value………………… 11,11
-                     *       ├─Units…………………………… °C
-                     *       └─Scale factor………… 1,5
-                     */
-                    final DefaultAttributeGroup attributeGroup = new DefaultAttributeGroup();
-                    attributeGroup.getContentTypes().add(CoverageContentType.AUXILLARY_INFORMATION);
-                    // Attributes
-                    final DefaultRangeDimension rangeDimension = new DefaultRangeDimension();
-                    rangeDimension.setDescription(new SimpleInternationalString("Population density"));
-                    rangeDimension.setSequenceIdentifier(Names.createMemberName(null, null, "42", Integer.class));
-                    rangeDimension.getNames().add(new DefaultIdentifier());
-                    final DefaultSampleDimension sampleDimension = new DefaultSampleDimension();
-                    sampleDimension.setDescription(new SimpleInternationalString("Temperature"));
-                    sampleDimension.setMinValue(11.11);
-                    sampleDimension.setMaxValue(22.22);
-                    sampleDimension.setUnits(Units.CELSIUS);
-                    sampleDimension.setScaleFactor(1.5);
-                    attributeGroup.setAttributes(Arrays.asList(rangeDimension, sampleDimension));
-                    coverageDescription.getAttributeGroups().add(attributeGroup);
-                }
-            }
-            // Feature Catalogue Description
-            final DefaultFeatureCatalogueDescription featureCatalogueDescription = new DefaultFeatureCatalogueDescription();
-            featureCatalogueDescription.setIncludedWithDataset(true);
-            featureCatalogueDescription.setCompliant(true);
-            md.setContentInfo(Arrays.asList(coverageDescription, featureCatalogueDescription));
-        }
-        return md;
-    }
-
-    /**
-     * Tests marshalling of an ISO 19139:2007 document (based on ISO 19115:2003 model).
-     * Current implementation merely tests that marshalling does not produce exception.
-     *
-     * @throws URISyntaxException if an error occurred while creating the metadata object.
-     * @throws JAXBException if an error occurred while marshalling the document.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
-     */
-    @Test
-    public void testLegacySchema() throws URISyntaxException, JAXBException {
-        legacyXML = true;
-        final DefaultMetadata md = metadata();
-        marshaller.setProperty(XML.METADATA_VERSION, VERSION_2007);
-        marshaller.marshal(md, output);
-        recycle();
-    }
-
-    /**
-     * Tests marshalling of an ISO 19115-3 document (based on ISO 19115:2014 model).
-     * Current implementation merely tests that marshalling does not produce exception.
-     *
-     * @throws URISyntaxException if an error occurred while creating the metadata object.
-     * @throws JAXBException if an error occurred while marshalling the document.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
-     */
-    @Test
-    public void testCurrentSchema() throws JAXBException, URISyntaxException {
-        final DefaultMetadata md = metadata();
-        marshaller.setProperty(XML.METADATA_VERSION, VERSION_2014);
-        marshaller.marshal(md, output);
-        recycle();
-    }
-
-    /**
-     * Invoked only on success, for recycling the marshaller.
-     */
-    private void recycle() {
-        pool.recycle(marshaller);
-    }
-
-    /**
-     * Invoked when a warning occurred while marshalling a test XML fragment. Expected warnings are
-     * "Can't find resource for bundle {@code java.util.PropertyResourceBundle}, key <cite>Foo</cite>".
-     * When marshalling legacy XML only, additional warnings may occur.
-     *
-     * @param  warning  the warning.
-     */
-    @Override
-    public boolean isLoggable(final LogRecord warning) {
-        if (warning.getThrown() instanceof MissingResourceException) {
-            assertNull("Expected a warning message without parameters.", warning.getParameters());
-            return false;
-        }
-        final String message = warning.getMessage();
-        if (legacyXML) {
-            assertEquals("IgnoredPropertiesAfterFirst_1", message);
-            assertArrayEquals(new String[] {"RangeDimension"}, warning.getParameters());
-        } else {
-            fail("Unexpected logging message: " + message);
-        }
-        return false;
-    }
-}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
index 98605b4..81be7ca 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
@@ -30,6 +30,7 @@
 import org.opengis.metadata.citation.Party;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
@@ -87,9 +88,15 @@
                 PresentationForm.DOCUMENT_DIGITAL));
         citation.setAlternateTitles(Collections.singleton(
                 new SimpleInternationalString("Andākarento")));   // Actually a different script of the Japanese title.
-        citation.setCitedResponsibleParties(Arrays.asList(
-                new DefaultResponsibility(Role.AUTHOR, null, new DefaultIndividual("Testsuya Toyoda", null, null)),
-                new DefaultResponsibility(Role.EDITOR, Extents.WORLD, new DefaultOrganisation("Kōdansha", null, null, null))));
+
+        final DefaultResponsibleParty author = new DefaultResponsibleParty(Role.AUTHOR);
+        author.setParties(Collections.singleton(new DefaultIndividual("Testsuya Toyoda", null, null)));
+
+        final DefaultResponsibleParty editor = new DefaultResponsibleParty(Role.EDITOR);
+        editor.setParties(Collections.singleton(new DefaultOrganisation("Kōdansha", null, null, null)));
+        editor.setExtents(Collections.singleton(Extents.WORLD));
+
+        citation.setCitedResponsibleParties(Arrays.asList(author, editor));
         return citation;
     }
 
@@ -239,7 +246,7 @@
      */
     private void testMarshalling(final String file, final Version version) throws JAXBException {
         final DefaultOnlineResource rs = new DefaultOnlineResource(URI.create("https://tools.ietf.org/html/rfc1149"));
-        rs.setName(new SimpleInternationalString("IP over Avian Carriers"));
+        rs.setName("IP over Avian Carriers");
         rs.setDescription(new SimpleInternationalString("High delay, low throughput, and low altitude service."));
         rs.setFunction(OnLineFunction.OFFLINE_ACCESS);
 
@@ -247,10 +254,11 @@
         contact.setContactInstructions(new SimpleInternationalString("Send carrier pigeon."));
         contact.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "ip-protocol");
         final DefaultCitation c = new DefaultCitation("Fight against poverty");
-        c.setCitedResponsibleParties(Arrays.asList(
-                new DefaultResponsibility(Role.ORIGINATOR, null, new DefaultIndividual("Maid Marian", null, contact)),
-                new DefaultResponsibility(Role.FUNDER,     null, new DefaultIndividual("Robin Hood",  null, contact))
-        ));
+        final DefaultResponsibleParty r1 = new DefaultResponsibleParty(Role.ORIGINATOR);
+        final DefaultResponsibleParty r2 = new DefaultResponsibleParty(Role.FUNDER);
+        r1.setParties(Collections.singleton(new DefaultIndividual("Maid Marian", null, contact)));
+        r2.setParties(Collections.singleton(new DefaultIndividual("Robin Hood",  null, contact)));
+        c.setCitedResponsibleParties(Arrays.asList(r1, r2));
         c.getDates().add(new DefaultCitationDate(TestUtilities.date("2015-10-17 00:00:00"), DateType.ADOPTED));
         c.getPresentationForms().add(PresentationForm.PHYSICAL_OBJECT);
         /*
@@ -301,7 +309,7 @@
         assertEquals("dateType", DateType.ADOPTED, date.getDateType());
         assertEquals("presentationForm", PresentationForm.PHYSICAL_OBJECT, getSingleton(c.getPresentationForms()));
 
-        final Iterator<Responsibility> it = c.getCitedResponsibleParties().iterator();
+        final Iterator<ResponsibleParty> it = c.getCitedResponsibleParties().iterator();
         final Contact contact = assertResponsibilityEquals(Role.ORIGINATOR, "Maid Marian", it.next());
         assertEquals("Contact instruction", "Send carrier pigeon.", String.valueOf(contact.getContactInstructions()));
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
index 1dabcbf..c1e7e2e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
@@ -44,8 +44,9 @@
     @Test
     public void testLegacyMarshalling() throws JAXBException {
         final DefaultIndividual  party = new DefaultIndividual("An author", null, null);
-        final DefaultResponsibility  r = new DefaultResponsibility(Role.AUTHOR, null, party);
+        final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.AUTHOR);
         final DefaultCitation citation = new DefaultCitation();
+        r.setParties(singleton(party));
         citation.setCitedResponsibleParties(singleton(r));
         final String xml = marshal(citation, VERSION_2007);
         assertXmlEquals("<gmd:CI_Citation xmlns:gco=\"" + LegacyNamespaces.GCO + '"' +
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
index 07fc075..286bb62 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
@@ -27,6 +27,8 @@
 import org.apache.sis.internal.util.URLs;
 import org.apache.sis.util.Static;
 
+import static java.util.Collections.singleton;
+
 
 /**
  * Hard-coded citation constants used for testing purpose only.
@@ -92,8 +94,9 @@
         final DefaultOnlineResource r = new DefaultOnlineResource(URI.create(URLs.EPSG));
         r.setFunction(OnLineFunction.INFORMATION);
 
-        final DefaultResponsibility p = new DefaultResponsibility(Role.PRINCIPAL_INVESTIGATOR, null,
-                new DefaultOrganisation("International Association of Oil & Gas Producers", null, null, new DefaultContact(r)));
+        final DefaultResponsibleParty p = new DefaultResponsibleParty(Role.PRINCIPAL_INVESTIGATOR);
+        p.setParties(singleton(new DefaultOrganisation("International Association of Oil & Gas Producers",
+                null, null, new DefaultContact(r))));
 
         final DefaultCitation c = new DefaultCitation("EPSG Geodetic Parameter Dataset");
         c.getPresentationForms().add(PresentationForm.TABLE_DIGITAL);
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/content/DefaultBandTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/content/DefaultBandTest.java
index b359fa5..84a76f0 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/content/DefaultBandTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/content/DefaultBandTest.java
@@ -17,7 +17,7 @@
 package org.apache.sis.metadata.iso.content;
 
 import javax.xml.bind.JAXBException;
-import org.opengis.metadata.content.PolarisationOrientation;
+import org.opengis.metadata.content.PolarizationOrientation;
 import org.apache.sis.util.Version;
 import org.apache.sis.test.xml.TestCase;
 import org.junit.Test;
@@ -101,7 +101,7 @@
         final DefaultBand band = new DefaultBand();
         band.setNumberOfValues(1000);
         band.setNominalSpatialResolution(10d);
-        band.setDetectedPolarisation(PolarisationOrientation.VERTICAL);
+        band.setDetectedPolarization(PolarizationOrientation.VERTICAL);
         final String actual = marshal(band, version);
         assertXmlEquals(expected, actual, "xmlns:*");
     }
@@ -135,7 +135,7 @@
     private void unmarshal(final String xml, final Integer numberOfValues) throws JAXBException {
         final DefaultBand band = unmarshal(DefaultBand.class, xml);
         assertEquals(Double.valueOf(10), band.getNominalSpatialResolution());
-        assertEquals(PolarisationOrientation.VERTICAL, band.getDetectedPolarisation());
+        assertEquals(PolarizationOrientation.VERTICAL, band.getDetectedPolarization());
         assertEquals(numberOfValues, band.getNumberOfValues());
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
index a174c40..5082ab5 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.metadata.iso.maintenance;
 
-import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.test.LoggingWatcher;
 import org.apache.sis.test.TestCase;
@@ -62,14 +61,14 @@
         assertEquals("dataset", "A dataset", metadata.getDataset());
         loggings.assertNoUnexpectedLog();
 
-        metadata.setOther(new SimpleInternationalString("Other value"));
-        assertEquals("other", "Other value", String.valueOf(metadata.getOther()));
+        metadata.setOther("Other value");
+        assertEquals("other", "Other value", metadata.getOther());
         assertNull("dataset", metadata.getDataset());
         loggings.assertNextLogContains("dataset", "other");
         loggings.assertNoUnexpectedLog();
 
         metadata.setDataset(null);                  // Expected to be a no-op.
-        assertEquals("other", "Other value", String.valueOf(metadata.getOther()));
+        assertEquals("other", "Other value", metadata.getOther());
         assertNull("dataset", metadata.getDataset());
 
         metadata.setOther(null);
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
index 55c19f4..e0179ef 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
@@ -79,7 +79,6 @@
             source.install();
             verifyFormats(source);
             testSearch(source);
-            testEmptyCollection(source);
             ensureReadOnly(source);
 
             // Opportunistic verification using the database we have at hand.
@@ -136,21 +135,6 @@
     }
 
     /**
-     * Verifies that empty collections are empty, not-null.
-     *
-     * @param  source  the instance to test.
-     * @throws MetadataStoreException if an error occurred while querying the database.
-     */
-    @TestStep
-    public static void testEmptyCollection(final MetadataSource source) throws MetadataStoreException {
-        final Citation c = source.lookup(Citation.class, "SIS");
-        final Collection<?> details = c.getOtherCitationDetails();
-        assertNotNull("Empty collection should not be null.", details);
-        assertTrue("Expected an empty collection.", details.isEmpty());
-        assertSame("Collection shall be unmodifiable.", Collections.EMPTY_LIST, details);
-    }
-
-    /**
      * Verifies that instances created by {@link MetadataSource} are read-only.
      * In particular, it should not be possible to add elements in the collection.
      *
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
index 23bf003..8880382 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
@@ -122,7 +122,7 @@
         assertEquals("EPSG",      source.search(HardCodedCitations.EPSG));
         assertEquals("SIS",       source.search(HardCodedCitations.SIS));
         assertNull  ("ISO 19111", source.search(HardCodedCitations.ISO_19111));
-        assertEquals("EPSG",      source.search(TestUtilities.getSingleton(
+        assertEquals("{rp}EPSG",  source.search(TestUtilities.getSingleton(
                 HardCodedCitations.EPSG.getCitedResponsibleParties())));
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
index a104e87..42e620b 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
@@ -23,8 +23,8 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.jaxb.gco.GO_GenericName;
@@ -42,7 +42,7 @@
  */
 @SuppressWarnings("serial")
 @XmlRootElement(name = "IO_IdentifiedObject")
-public strictfp class IdentifiedObjectMock implements IdentifiedObject, Identifier, Serializable {
+public strictfp class IdentifiedObjectMock implements IdentifiedObject, ReferenceIdentifier, Serializable {
     /**
      * The object name to be returned by {@link #getCode()}.
      */
@@ -100,7 +100,7 @@
      * @return the name of this object, or {@code null} if none.
      */
     @Override
-    public final Identifier getName() {
+    public final ReferenceIdentifier getName() {
         return (code != null) ? this : null;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
index af4efdc..2711a6c 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
@@ -128,7 +128,6 @@
     org.apache.sis.metadata.iso.DefaultMetadataTest.class,
     org.apache.sis.metadata.iso.CustomMetadataTest.class,
     org.apache.sis.metadata.iso.AllMetadataTest.class,
-    org.apache.sis.metadata.iso.MarshallingTest.class,
     org.apache.sis.metadata.iso.APIVerifier.class,
 
     org.apache.sis.internal.metadata.sql.SQLUtilitiesTest.class,
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
index 0b8b755..f9d8a2e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
@@ -491,7 +491,7 @@
          * We check only the namespace start, since some specifications define many namespaces
          * under a common root (e.g. "http://standards.iso.org/iso/19115/-3/").
          */
-        if (uml != null) {
+        if (uml != null && false) {     // This verification is available only on development branches.
             final String expected = getExpectedNamespaceStart(impl, uml);
             if (!namespace.startsWith(expected)) {
                 fail("Expected " + expected + "… namespace for that ISO specification but got " + namespace);
@@ -561,6 +561,18 @@
     protected boolean isIgnored(final Method method) {
         switch (method.getName()) {
             /*
+             * Spelling changed.
+             */
+            case "getCenterPoint": {
+                return true;
+            }
+            /*
+             * Method that override an annotated method in parent class.
+             */
+            case "getUnits": {
+                return org.opengis.metadata.content.Band.class.isAssignableFrom(method.getDeclaringClass());
+            }
+            /*
              * Types for which JAXB binding has not yet implemented.
              */
             case "getGeographicCoordinates": {
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/PackageVerifier.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/PackageVerifier.java
index 7150ec3..690edc5 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/PackageVerifier.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/PackageVerifier.java
@@ -408,6 +408,9 @@
                     } else {
                         final Class<?>[] p = c.getInterfaces();
                         if (p.length == 0) {
+                            if (valueType == org.opengis.metadata.Obligation.class)  {
+                                break;
+                            }
                             throw new SchemaException(errorInClassMember(javaName)
                                     .append("Missing @XmlJavaTypeAdapter for ").append(valueType).toString());
                         }
@@ -512,20 +515,4 @@
         }
         return builder.append(':').append(System.lineSeparator());
     }
-
-    /**
-     * Verifies if there is any unused namespace or adapter in package-info file.
-     */
-    final void reportUnused() throws SchemaException {
-        for (final Map.Entry<String,Boolean> entry : namespaceIsUsed.entrySet()) {
-            if (!entry.getValue()) {
-                throw new SchemaException(String.format("Unused namespace in package %s:%n%s", packageName, entry.getKey()));
-            }
-        }
-        for (final Map.Entry<Class<?>,Boolean> entry : adapterIsUsed.entrySet()) {
-            if (!entry.getValue()) {
-                throw new SchemaException(String.format("Unused adapter in package %s for %s.", packageName, entry.getKey()));
-            }
-        }
-    }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/SchemaCompliance.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/SchemaCompliance.java
index 0389c97..35cfbaa 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/SchemaCompliance.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/SchemaCompliance.java
@@ -144,9 +144,6 @@
         } catch (DirectoryIteratorException e) {
             throw e.getCause();
         }
-        if (verifier != null) {
-            verifier.reportUnused();
-        }
     }
 
     /**
diff --git a/core/sis-portrayal/pom.xml b/core/sis-portrayal/pom.xml
index 521d22b..b7ad53a 100644
--- a/core/sis-portrayal/pom.xml
+++ b/core/sis-portrayal/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-referencing-by-identifiers/pom.xml b/core/sis-referencing-by-identifiers/pom.xml
index 7efb970..78e1c0c 100644
--- a/core/sis-referencing-by-identifiers/pom.xml
+++ b/core/sis-referencing-by-identifiers/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.core</groupId>
diff --git a/core/sis-referencing/pom.xml b/core/sis-referencing/pom.xml
index 0936701..8fbaa28 100644
--- a/core/sis-referencing/pom.xml
+++ b/core/sis-referencing/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.core</groupId>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
index f3ecbd4..0de9cc7 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
@@ -27,6 +27,7 @@
 import javax.xml.bind.annotation.XmlElementRef;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.GeneralParameterDescriptor;
@@ -261,7 +262,7 @@
         final Map<String,Object> merged = new HashMap<>(expected);
         merged.putAll(actual);  // May overwrite pre-defined properties.
         mergeArrays(GeneralParameterDescriptor.ALIAS_KEY,       GenericName.class, provided.getAlias(),       merged, complete.getName());
-        mergeArrays(GeneralParameterDescriptor.IDENTIFIERS_KEY, Identifier.class,  provided.getIdentifiers(), merged, null);
+        mergeArrays(GeneralParameterDescriptor.IDENTIFIERS_KEY, ReferenceIdentifier.class, provided.getIdentifiers(), merged, null);
         if (isGroup) {
             final List<GeneralParameterDescriptor> descriptors = ((ParameterDescriptorGroup) provided).descriptors();
             return merge(DefaultParameterValueGroup.class, merged, merged, minimumOccurs, maximumOccurs,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
index 3d51b46..3c2eedb 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
@@ -21,6 +21,7 @@
 import javax.xml.bind.annotation.XmlAttribute;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.DefinitionURI;
 import org.apache.sis.internal.metadata.NameMeaning;
@@ -96,7 +97,7 @@
      *
      * @return the identifier, or {@code null} if none.
      */
-    public Identifier getIdentifier() {
+    public ReferenceIdentifier getIdentifier() {
         String c = code;
         if (c == null) {
             return null;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
index 81f23d5..cac8734 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
@@ -18,7 +18,7 @@
 
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.xml.NilReason;
 import org.apache.sis.xml.NilObject;
 import org.apache.sis.referencing.NamedIdentifier;
@@ -49,7 +49,7 @@
      *
      * @since 0.6
      */
-    public static final Identifier UNNAMED = new NamedIdentifier(null, Vocabulary.format(Vocabulary.Keys.Unnamed));
+    public static final ReferenceIdentifier UNNAMED = new NamedIdentifier(null, Vocabulary.format(Vocabulary.Keys.Unnamed));
 
     /**
      * The unique instance.
@@ -75,6 +75,6 @@
      * Returning null for collection are okay in the particular case of SIS implementation,
      * because the constructor will replace empty collections by null references anyway.
      */
-    @Override public Identifier          getName()  {return UNNAMED;}
+    @Override public ReferenceIdentifier getName()  {return UNNAMED;}
     @Override public InternationalString getScope() {return null;}
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
index 3a80362..eb2e7aa 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
@@ -21,7 +21,6 @@
 import java.util.Collection;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.IdentifiedObject;
@@ -45,6 +44,9 @@
 
 import static java.util.logging.Logger.getLogger;
 
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
 
 /**
  * Base class for all providers defined in this package.
@@ -154,10 +156,10 @@
         ArgumentChecks.ensureNonNull("parameters", parameters);
         final Map<String,Object> properties = new HashMap<>(4);
         properties.put(NAME_KEY, parameters.getName());
-        final Collection<Identifier> identifiers = parameters.getIdentifiers();
+        final Collection<ReferenceIdentifier> identifiers = parameters.getIdentifiers();
         int size = identifiers.size();
         if (size != 0) {
-            properties.put(IDENTIFIERS_KEY, identifiers.toArray(new Identifier[size]));
+            properties.put(IDENTIFIERS_KEY, identifiers.toArray(new ReferenceIdentifier[size]));
         }
         final Collection<GenericName> aliases = parameters.getAlias();
         size = aliases.size();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
index 7f05053..ee3c81f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
@@ -37,6 +37,7 @@
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.measure.MeasurementRange;
@@ -379,12 +380,12 @@
             }
             builder.addName(alias);
         }
-        for (Identifier id : template.getIdentifiers()) {
+        for (ReferenceIdentifier id : template.getIdentifiers()) {
             final Citation authority = id.getAuthority();
             for (int i=0; i<toRename.length; i++) {
                 if (authority == toRename[i]) {
                     if (newCodes[i] == null) continue;
-                    id = newCodes[i];
+                    id = (ReferenceIdentifier) newCodes[i];
                     newCodes[i] = null;
                     break;
                 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
index 762964b..2dbc218 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
@@ -24,6 +24,9 @@
 
 import static org.apache.sis.referencing.IdentifiedObjects.getIdentifier;
 
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
 
 /**
  * The provider for <cite>"Hotine Oblique Mercator (variant B)"</cite> projection (EPSG:9815).
@@ -117,7 +120,7 @@
                 .addName      (Citations.S57,     "OME")
                 .addIdentifier(Citations.S57,     "9")
                 .addName      (Citations.GEOTIFF, "CT_ObliqueMercator")
-                .addIdentifier(getIdentifier(PARAMETERS_A, Citations.GEOTIFF))      // Same GeoTIFF identifier.
+                .addIdentifier((ReferenceIdentifier) getIdentifier(PARAMETERS_A, Citations.GEOTIFF))      // Same GeoTIFF identifier.
                 .addName      (Citations.PROJ4,   "omerc")
                 .createGroupForMapProjection(
                         LATITUDE_OF_CENTRE,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
index 1f5b3b8..320aebd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
@@ -43,6 +43,7 @@
 import org.opengis.util.ControlledVocabulary;
 import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.OperationMethod;
 
 import org.apache.sis.measure.Range;
@@ -847,7 +848,7 @@
              * Put the first identifier in the first column. If no identifier has a codespace in the list
              * supplied by the user, then we will use the first identifier (any codespace) as a fallback.
              */
-            final Set<Identifier> identifiers = object.getIdentifiers();
+            final Set<ReferenceIdentifier> identifiers = object.getIdentifiers();
             if (identifiers != null) {                                              // Paranoiac check.
                 Identifier identifier = null;
                 for (final Identifier candidate : identifiers) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
index 285fc7f..92341bf 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
@@ -70,6 +70,9 @@
 import static org.apache.sis.internal.util.CollectionsExt.nonEmpty;
 import static org.apache.sis.internal.util.CollectionsExt.immutableSet;
 
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
 
 /**
  * Base class for objects identified by a name or a code. Those objects are typically
@@ -112,7 +115,7 @@
  * </ul>
  *
  * <h2>Immutability and thread safety</h2>
- * This base class is immutable if the {@link Citation}, {@link Identifier}, {@link GenericName} and
+ * This base class is immutable if the {@link Citation}, {@link ReferenceIdentifier}, {@link GenericName} and
  * {@link InternationalString} instances given to the constructor are also immutable. Most SIS subclasses and
  * related classes are immutable under similar conditions. This means that unless otherwise noted in the javadoc,
  * {@code IdentifiedObject} instances created using only SIS factories and static constants can be shared by many
@@ -173,12 +176,12 @@
      * The name for this object or code. Shall never be {@code null}.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
+     * This field is modified only at unmarshalling time by {@code Names.add(Identifier)}.</p>
      *
      * @see #getName()
      * @see #getNames()
      */
-    private Identifier name;
+    private ReferenceIdentifier name;
 
     /**
      * An alternative name by which this object is identified, or {@code null} if none.
@@ -186,7 +189,7 @@
      * we may get both on unmarshalling.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
+     * This field is modified only at unmarshalling time by {@code Names.add(Identifier)}.</p>
      */
     private Collection<GenericName> alias;
 
@@ -200,7 +203,7 @@
      * @see #getIdentifiers()
      * @see #getIdentifier()
      */
-    private Set<Identifier> identifiers;
+    private Set<ReferenceIdentifier> identifiers;
 
     /**
      * Comments on or information about this object, or {@code null} if none.
@@ -235,7 +238,7 @@
      * Other properties listed in the table below are optional.
      * In particular, {@code "authority"}, {@code "code"}, {@code "codespace"} and {@code "version"}
      * are convenience properties for building a name, and are ignored if the {@code "name"} property
-     * is already a {@link Identifier} object instead of a {@link String}.
+     * is already a {@link ReferenceIdentifier} object instead of a {@link String}.
      *
      * <table class="sis">
      *   <caption>Recognized properties (non exhaustive list)</caption>
@@ -246,7 +249,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link Identifier} or {@link String}</td>
+     *     <td>{@link ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -260,12 +263,12 @@
      *     <td>{@link NamedIdentifier#getCode()} on the {@linkplain #getName() name}</td>
      *   </tr>
      *   <tr>
-     *     <td>{@value org.opengis.metadata.Identifier#CODESPACE_KEY}</td>
+     *     <td>{@value org.opengis.referencing.ReferenceIdentifier#CODESPACE_KEY}</td>
      *     <td>{@link String}</td>
      *     <td>{@link NamedIdentifier#getCodeSpace()} on the {@linkplain #getName() name}</td>
      *   </tr>
      *   <tr>
-     *     <td>{@value org.opengis.metadata.Identifier#VERSION_KEY}</td>
+     *     <td>{@value org.opengis.referencing.ReferenceIdentifier#VERSION_KEY}</td>
      *     <td>{@link String}</td>
      *     <td>{@link NamedIdentifier#getVersion()} on the {@linkplain #getName() name}</td>
      *   </tr>
@@ -281,7 +284,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link Identifier} (optionally as array)</td>
+     *     <td>{@link ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -332,8 +335,8 @@
                         .getString(Errors.Keys.MissingValueForProperty_1, NAME_KEY));
             }
             name = new NamedIdentifier(PropertiesConverter.convert(properties));
-        } else if (value instanceof Identifier) {
-            name = (Identifier) value;
+        } else if (value instanceof ReferenceIdentifier) {
+            name = (ReferenceIdentifier) value;
         } else {
             throw illegalPropertyType(properties, NAME_KEY, value);
         }
@@ -362,10 +365,10 @@
         value = properties.get(IDENTIFIERS_KEY);
         if (value == null) {
             identifiers = null;
-        } else if (value instanceof Identifier) {
-            identifiers = Collections.singleton((Identifier) value);
-        } else if (value instanceof Identifier[]) {
-            identifiers = immutableSet(true, (Identifier[]) value);
+        } else if (value instanceof ReferenceIdentifier) {
+            identifiers = Collections.singleton((ReferenceIdentifier) value);
+        } else if (value instanceof ReferenceIdentifier[]) {
+            identifiers = immutableSet(true, (ReferenceIdentifier[]) value);
         } else {
             throw illegalPropertyType(properties, IDENTIFIERS_KEY, value);
         }
@@ -483,7 +486,7 @@
      * @see IdentifiedObjects#getName(IdentifiedObject, Citation)
      */
     @Override
-    public Identifier getName() {
+    public ReferenceIdentifier getName() {
         return name;
     }
 
@@ -508,7 +511,7 @@
      * @see IdentifiedObjects#getIdentifier(IdentifiedObject, Citation)
      */
     @Override
-    public Set<Identifier> getIdentifiers() {
+    public Set<ReferenceIdentifier> getIdentifiers() {
         return nonNull(identifiers);    // Needs to be null-safe because we may have a null value on unmarshalling.
     }
 
@@ -998,7 +1001,7 @@
     private void setIdentifier(final Code identifier) {
         if (identifiers == null) {
             if (identifier != null) {
-                final Identifier id = identifier.getIdentifier();
+                final ReferenceIdentifier id = identifier.getIdentifier();
                 if (id != null) {
                     identifiers = Collections.singleton(id);
                 }
@@ -1026,7 +1029,7 @@
      * @see <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a>
      */
     @XmlElement(name = "name", required = true)
-    final Collection<Identifier> getNames() {
+    final Collection<ReferenceIdentifier> getNames() {
         return new Names();
     }
 
@@ -1043,7 +1046,7 @@
      * subclasses, this is too late. For example {@code DefaultOperationMethod} may need to know the operation name
      * before to parse the parameters.
      */
-    private final class Names extends AbstractCollection<Identifier> {
+    private final class Names extends AbstractCollection<ReferenceIdentifier> {
         /**
          * Invoked by JAXB before to write in the collection at unmarshalling time.
          * Do nothing since our object is already empty.
@@ -1064,7 +1067,7 @@
          * Returns an iterator over the name and aliases that are instance of {@link Identifier}.
          */
         @Override
-        public Iterator<Identifier> iterator() {
+        public Iterator<ReferenceIdentifier> iterator() {
             return new NameIterator(AbstractIdentifiedObject.this);
         }
 
@@ -1078,7 +1081,7 @@
          * See <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a> for more information.</p>
          */
         @Override
-        public boolean add(final Identifier id) {
+        public boolean add(final ReferenceIdentifier id) {
             if (NameIterator.isUnnamed(name)) {
                 name = id;
             } else {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
index 50eb321..5f4fba9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
@@ -40,6 +40,9 @@
 
 import static org.apache.sis.util.ArgumentChecks.*;
 
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
 
 /**
  * Base class of builders for various kinds of {@link IdentifiedObject}. This class provides convenience methods
@@ -92,7 +95,7 @@
  *       The result is a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} or identifier,
  *       in which the code space information is shown by the {@code toString()} method.</li>
  *
- *   <li>The {@link #addIdentifier(Identifier)}, {@link #addName(Identifier)} and {@link #addName(GenericName)}
+ *   <li>The {@code addIdentifier(Identifier)}, {@code addName(Identifier)} and {@link #addName(GenericName)}
  *       methods take the given object <cite>as-is</cite>. Any authority, code space, version or description
  *       information given to the {@code Builder} are ignored.</li>
  * </ul>
@@ -201,7 +204,7 @@
     /**
      * A temporary list for identifiers, before to assign them to the {@link #properties}.
      */
-    private final List<Identifier> identifiers;
+    private final List<ReferenceIdentifier> identifiers;
 
     /**
      * The codespace as a {@code NameSpace} object, or {@code null} if not yet created.
@@ -272,7 +275,7 @@
         if (object != null) {
             properties.putAll(IdentifiedObjects.getProperties(object));
             final GenericName[] valueAlias = (GenericName[]) properties.remove(IdentifiedObject.ALIAS_KEY);
-            final Identifier[]  valueIds   = (Identifier[])  properties.remove(IdentifiedObject.IDENTIFIERS_KEY);
+            final ReferenceIdentifier[] valueIds = (ReferenceIdentifier[]) properties.remove(IdentifiedObject.IDENTIFIERS_KEY);
             if (valueAlias != null) aliases.addAll(Arrays.asList(valueAlias));
             if (valueIds != null) identifiers.addAll(Arrays.asList(valueIds));
         }
@@ -321,7 +324,7 @@
      * then the new identifier will also contain the user-supplied code space and version (if any).
      * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
      */
-    private Identifier createIdentifier(final Citation authority, final String identifier) {
+    private ReferenceIdentifier createIdentifier(final Citation authority, final String identifier) {
         final String codeSpace;
         final String version;
         if (authority == getAuthority()) {
@@ -339,7 +342,9 @@
      * Creates an identifier for the given authority, code space and version.
      * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
      */
-    private Identifier createIdentifier(final Citation authority, final String codeSpace, final String identifier, final String version) {
+    private ReferenceIdentifier createIdentifier(final Citation authority,
+            final String codeSpace, final String identifier, final String version)
+    {
         if (isDeprecated()) {
             return new DeprecatedCode(authority, codeSpace, identifier, version, null, getRemarks());
         } else {
@@ -351,8 +356,8 @@
      * Converts the given name into an identifier. Note that {@link NamedIdentifier}
      * implements both {@link GenericName} and {@link Identifier} interfaces.
      */
-    private static Identifier toIdentifier(final GenericName name) {
-        return (name instanceof Identifier) ? (Identifier) name : new NamedIdentifier(name);
+    private static ReferenceIdentifier toIdentifier(final GenericName name) {
+        return (name instanceof ReferenceIdentifier) ? (ReferenceIdentifier) name : new NamedIdentifier(name);
     }
 
     /**
@@ -583,7 +588,7 @@
      * @param  name  the {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
-    public B addName(final Identifier name) {
+    public B addName(final ReferenceIdentifier name) {
         ensureNonNull("name", name);
         if (properties.putIfAbsent(IdentifiedObject.NAME_KEY, name) != null) {
             // A primary name is already present. Add the given name as an alias instead.
@@ -675,7 +680,7 @@
      * @param  identifier  the {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
-    public B addIdentifier(final Identifier identifier) {
+    public B addIdentifier(final ReferenceIdentifier identifier) {
         ensureNonNull("identifier", identifier);
         identifiers.add(identifier);
         return self();
@@ -705,12 +710,12 @@
      */
     public B addNamesAndIdentifiers(final IdentifiedObject object) {
         ensureNonNull("object", object);
-        for (final Identifier id : object.getIdentifiers()) {
+        for (final ReferenceIdentifier id : object.getIdentifiers()) {
             if (isValid(id)) {
                 addIdentifier(id);
             }
         }
-        Identifier id = object.getName();
+        ReferenceIdentifier id = object.getName();
         if (isValid(id)) {
             addName(id);
         }
@@ -735,12 +740,12 @@
     public B addNameAndIdentifier(final Citation authority, final IdentifiedObject object) {
         ensureNonNull("authority", authority);
         ensureNonNull("object", object);
-        for (final Identifier id : object.getIdentifiers()) {
+        for (final ReferenceIdentifier id : object.getIdentifiers()) {
             if (isValid(id) && authority.equals(id.getAuthority())) {
                 addIdentifier(id);
             }
         }
-        Identifier id = object.getName();
+        ReferenceIdentifier id = object.getName();
         if (isValid(id) && authority.equals(id.getAuthority())) {
             addName(id);
         }
@@ -1049,7 +1054,7 @@
             valueIds   = null;
         } else {
             valueAlias = aliases    .toArray(new GenericName[aliases    .size()]);
-            valueIds   = identifiers.toArray(new Identifier [identifiers.size()]);
+            valueIds   = identifiers.toArray(new ReferenceIdentifier[identifiers.size()]);
         }
         properties.put(IdentifiedObject.ALIAS_KEY,       valueAlias);
         properties.put(IdentifiedObject.IDENTIFIERS_KEY, valueIds);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index 18e19da..a19ea82 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -560,12 +560,12 @@
              */
             if (Double.isNaN(roiArea) || maxInsideArea < roiArea) {
                 if (tryDerivedCRS) break;                                               // Do not try twice.
-                final SingleCRS[] derivedCRS = new SingleCRS[sourceCRS.length];
+                final CoordinateReferenceSystem[] derivedCRS = new CoordinateReferenceSystem[sourceCRS.length];
                 for (int i=0; i < derivedCRS.length; i++) {
                     GeographicBoundingBox bbox = null;
                     final CoordinateReferenceSystem crs = sourceCRS[i];
                     if (crs instanceof GeneralDerivedCRS) {
-                        final SingleCRS baseCRS = ((GeneralDerivedCRS) crs).getBaseCRS();
+                        final CoordinateReferenceSystem baseCRS = ((GeneralDerivedCRS) crs).getBaseCRS();
                         bbox = getGeographicBoundingBox(baseCRS);
                         if (bbox == null && bestCRS == null && baseCRS instanceof GeodeticCRS) {
                             bestCRS = baseCRS;      // Fallback to be used if we don't find anything better.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
index 2cb778b..6166e4f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
@@ -22,6 +22,7 @@
 import java.io.Serializable;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
@@ -111,7 +112,7 @@
  * @module
  */
 @TitleProperty(name = "code")
-public class ImmutableIdentifier extends FormattableObject implements Identifier, Serializable {
+public class ImmutableIdentifier extends FormattableObject implements ReferenceIdentifier, Serializable {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
index dfce1d0..58e43a3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
@@ -19,8 +19,8 @@
 import java.util.Iterator;
 import java.util.Collection;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.referencing.NilReferencingObject;
@@ -30,7 +30,7 @@
 
 /**
  * An iterator over the {@linkplain IdentifiedObject#getName() name} of an identified object followed by
- * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link Identifier}.
+ * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link ReferenceIdentifier}.
  * This iterator is used for {@link AbstractIdentifiedObject} XML marshalling because GML merges the name
  * and aliases in a single {@code <gml:name>} property. However this iterator is useful only if the aliases
  * are instances of {@link NamedIdentifier}, or any other implementation which is both a name and an identifier.
@@ -42,11 +42,11 @@
  * @since   0.4
  * @module
  */
-final class NameIterator implements Iterator<Identifier> {
+final class NameIterator implements Iterator<ReferenceIdentifier> {
     /**
      * The next element to return, or {@code null} if we reached the end of iteration.
      */
-    private Identifier next;
+    private ReferenceIdentifier next;
 
     /**
      * An iterator over the aliases.
@@ -68,7 +68,7 @@
     /**
      * Returns {@code true} if the given identifier is null or the {@link NilReferencingObject#UNNAMED} instance.
      */
-    static boolean isUnnamed(final Identifier name) {
+    static boolean isUnnamed(final ReferenceIdentifier name) {
         return (name == null) || (name == NilReferencingObject.UNNAMED);
     }
 
@@ -87,12 +87,12 @@
      * will be used only by JAXB, which is presumed checking for {@link #hasNext()} correctly.
      */
     @Override
-    public Identifier next() {
-        final Identifier n = next;
+    public ReferenceIdentifier next() {
+        final ReferenceIdentifier n = next;
         while (alias.hasNext()) {
             final GenericName c = alias.next();
-            if (c instanceof Identifier) {
-                next = (Identifier) c;
+            if (c instanceof ReferenceIdentifier) {
+                next = (ReferenceIdentifier) c;
                 return n;
             }
         }
@@ -144,8 +144,8 @@
      * @param  identifiers  the identifiers, or {@code null} if none.
      * @return proposed value for {@code gml:id} attribute, or {@code null} if none.
      */
-    static String getID(final Context context, final IdentifiedObject object, final Identifier name,
-            final Collection<? extends GenericName> alias, final Collection<? extends Identifier> identifiers)
+    static String getID(final Context context, final IdentifiedObject object, final ReferenceIdentifier name,
+            final Collection<? extends GenericName> alias, final Collection<? extends ReferenceIdentifier> identifiers)
     {
         String candidate = Context.getObjectID(context, object);
         if (candidate == null) {
@@ -155,7 +155,7 @@
              * if we found no suitable ID, then we will use the primary name as a last resort.
              */
             if (identifiers != null) {
-                for (final Identifier identifier : identifiers) {
+                for (final ReferenceIdentifier identifier : identifiers) {
                     if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), "", true) |    // Really |, not ||
                         appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(object.getClass()), "", false) |
                         appendUnicodeIdentifier(id, '-', identifier.getCode(), "", true))
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
index 916f115..80cda06 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
@@ -32,6 +32,7 @@
 import org.apache.sis.util.resources.Errors;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.InvalidParameterValueException;
 import org.apache.sis.internal.metadata.NameToIdentifier;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -93,7 +94,7 @@
  * @since 0.4
  * @module
  */
-public class NamedIdentifier extends ImmutableIdentifier implements GenericName {
+public class NamedIdentifier extends ImmutableIdentifier implements GenericName, ReferenceIdentifier {
     /**
      * Serial number for inter-operability with different versions.
      */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
index 6ad7f91..de893f1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
@@ -21,10 +21,10 @@
 import java.util.Collection;
 import java.io.Serializable;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.SingleOperation;
@@ -128,11 +128,11 @@
                     return object.getName();
                 }
                 case 1: {   // IDENTIFIERS_KEY
-                    final Collection<Identifier> c = object.getIdentifiers();
+                    final Collection<ReferenceIdentifier> c = object.getIdentifiers();
                     if (c != null) {
                         final int size = c.size();
                         if (size != 0) {
-                            return c.toArray(new Identifier[size]);
+                            return c.toArray(new ReferenceIdentifier[size]);
                         }
                     }
                     break;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
index 5c8fdb5..8962a72 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
@@ -145,7 +145,7 @@
      */
     AbstractDerivedCRS(final GeneralDerivedCRS crs) {
         super(crs);
-        conversionFromBase = createConversionFromBase(null, crs.getBaseCRS(), crs.getConversionFromBase());
+        conversionFromBase = createConversionFromBase(null, (SingleCRS) crs.getBaseCRS(), crs.getConversionFromBase());
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
index 561d191..f8e57da 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
@@ -378,7 +378,7 @@
         if (object == null || object instanceof DefaultDerivedCRS) {
             return (DefaultDerivedCRS) object;
         } else {
-            final String type = getType(object.getBaseCRS(), object.getCoordinateSystem());
+            final String type = getType((SingleCRS) object.getBaseCRS(), object.getCoordinateSystem());
             if (type != null) switch (type) {
                 case WKTKeywords.GeodeticCRS:    return new Geodetic   (object);
                 case WKTKeywords.VerticalCRS:    return new Vertical   (object);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
index 6cbcacf..42aaad4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
@@ -223,7 +223,7 @@
     @XmlElement(name = "baseGeodeticCRS", required = true)        // Note: older GML version used "baseGeographicCRS".
     public GeographicCRS getBaseCRS() {
         final Projection projection = super.getConversionFromBase();
-        return (projection != null) ? projection.getSourceCRS() : null;
+        return (projection != null) ? (GeographicCRS) projection.getSourceCRS() : null;
     }
 
     /**
@@ -276,7 +276,7 @@
     @Override
     final AbstractCRS createSameType(final Map<String,?> properties, final CoordinateSystem cs) {
         final Projection conversion = super.getConversionFromBase();
-        return new DefaultProjectedCRS(properties, conversion.getSourceCRS(), conversion, (CartesianCS) cs);
+        return new DefaultProjectedCRS(properties, (GeographicCRS) conversion.getSourceCRS(), conversion, (CartesianCS) cs);
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
index 193c695..674b34d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
@@ -326,7 +326,7 @@
              */
             final Condition filter;
             if (object instanceof GeneralDerivedCRS) {              // No need to use isInstance(Class, Object) from here.
-                filter = dependencies("SOURCE_GEOGCRS_CODE", SingleCRS.class, ((GeneralDerivedCRS) object).getBaseCRS(), true);
+                filter = dependencies("SOURCE_GEOGCRS_CODE", CoordinateReferenceSystem.class, ((GeneralDerivedCRS) object).getBaseCRS(), true);
             } else if (object instanceof GeodeticCRS) {
                 filter = dependencies("DATUM_CODE", GeodeticDatum.class, ((GeodeticCRS) object).getDatum(), true);
             } else if (object instanceof VerticalCRS) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index f61f85d..d709744 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@ -995,8 +995,23 @@
             final int numTrailingCoordinates = remainingSourceDimensions - endAtDimension;
             CoordinateOperation subOperation = info.operation;
             if ((startAtDimension | numTrailingCoordinates) != 0) {
-                subOperation = new DefaultPassThroughOperation(IdentifiedObjects.getProperties(subOperation),
-                        stepSourceCRS, stepTargetCRS, subOperation, startAtDimension, numTrailingCoordinates);
+                final Map<String,?> properties = IdentifiedObjects.getProperties(subOperation);
+                /*
+                 * The DefaultPassThroughOperation constuctor expect a SingleOperation.
+                 * In most case, the 'subOperation' is already of this kind. However if
+                 * it is not, try to copy it in such object.
+                 */
+                final SingleOperation op;
+                if (SubTypes.isSingleOperation(subOperation)) {
+                    op = (SingleOperation) subOperation;
+                } else {
+                    final MathTransform subTransform = subOperation.getMathTransform();
+                    op = factorySIS.createSingleOperation(properties,
+                            subOperation.getSourceCRS(), subOperation.getTargetCRS(), null,
+                            new DefaultOperationMethod(subTransform), subTransform);
+                }
+                subOperation = new DefaultPassThroughOperation(properties, stepSourceCRS, stepTargetCRS,
+                        op, startAtDimension, numTrailingCoordinates);
             }
             /*
              * Concatenate the operation with the ones we have found so far, and use the current `stepTargetCRS`
@@ -1120,7 +1135,7 @@
             if (isAxisChange1 && mt1.getSourceDimensions() == mt1.getTargetDimensions()) main = step2;
             if (isAxisChange2 && mt2.getSourceDimensions() == mt2.getTargetDimensions()) main = step1;
         }
-        if (main instanceof SingleOperation) {
+        if (SubTypes.isSingleOperation(main)) {
             final SingleOperation op = (SingleOperation) main;
             final MathTransform mt = factorySIS.getMathTransformFactory().createConcatenatedTransform(mt1, mt2);
             main = createFromMathTransform(new HashMap<>(IdentifiedObjects.getProperties(main)),
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index 52a76c2..51ea821 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -752,7 +752,7 @@
     private CoordinateOperation inverse(final CoordinateOperation operation)
             throws NoninvertibleTransformException, FactoryException
     {
-        if (operation instanceof SingleOperation) {
+        if (SubTypes.isSingleOperation(operation)) {
             return inverse((SingleOperation) operation);
         }
         if (operation instanceof ConcatenatedOperation) {
@@ -934,7 +934,7 @@
          * be prepared to see the `redimension` call fails. In such case, we will try to get
          * the SIS implementation of the operation method and try again.
          */
-        if (operation instanceof SingleOperation) {
+        if (SubTypes.isSingleOperation(operation)) {
             final SingleOperation single = (SingleOperation) operation;
             properties.put(CoordinateOperations.PARAMETERS_KEY, single.getParameterValues());
             if (method == null) {
@@ -1095,7 +1095,7 @@
              */
             Matrix matrix = MathTransforms.getMatrix(op.getMathTransform());
             if (matrix == null) {
-                if (op instanceof SingleOperation) {
+                if (SubTypes.isSingleOperation(op)) {
                     final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
                     if (mtFactory instanceof DefaultMathTransformFactory) {
                         if (forward) sourceCRS = toGeodetic3D(sourceCRS, source3D);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
index 3899107..e5366a4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
@@ -45,6 +45,7 @@
 
 import static org.apache.sis.util.Utilities.deepEquals;
 
+import org.opengis.referencing.operation.SingleOperation;
 
 /**
  * An ordered sequence of two or more single coordinate operations. The sequence of operations is constrained
@@ -72,7 +73,7 @@
      * <p><b>Consider this field as final!</b>
      * This field is modified only at unmarshalling time by {@link #setSteps(CoordinateOperation[])}</p>
      */
-    private List<? extends CoordinateOperation> operations;
+    private List<SingleOperation> operations;
 
     /**
      * Constructs a concatenated operation from a set of properties and a
@@ -144,7 +145,7 @@
          * At this point we should have flattened.size() >= 2, except if some operations
          * were omitted because their associated math transform were identity operation.
          */
-        this.operations = UnmodifiableArrayList.wrap(flattened.toArray(new CoordinateOperation[flattened.size()]));
+        this.operations = UnmodifiableArrayList.wrap(flattened.toArray(new SingleOperation[flattened.size()]));
     }
 
     /**
@@ -333,11 +334,17 @@
     /**
      * Returns the sequence of operations.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method is conformant to ISO 19111:2003. But the ISO 19111:2007 revision changed the element type
+     * from {@code SingleOperation} to {@link CoordinateOperation}. This change may be applied in GeoAPI 4.0.
+     * This is necessary for supporting usage of {@code PassThroughOperation} with {@link ConcatenatedOperation}.
+     * </div>
+     *
      * @return the sequence of operations.
      */
     @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public List<? extends CoordinateOperation> getOperations() {
+    public List<SingleOperation> getOperations() {
         return operations;
     }
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
index 717129a..38e0cfb 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
@@ -22,6 +22,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.PassThroughOperation;
@@ -40,6 +41,8 @@
 
 import static org.apache.sis.util.Utilities.deepEquals;
 
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 
 /**
  * Specifies that a subset of a coordinate tuple is subject to a specific coordinate operation.
@@ -64,11 +67,11 @@
      * The operation to apply on the subset of a coordinate tuple.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@link #setOperation(CoordinateOperation)}</p>
+     * This field is modified only at unmarshalling time by {@code setOperation(CoordinateOperation)}</p>
      *
      * @see #getOperation()
      */
-    private CoordinateOperation operation;
+    private SingleOperation operation;
 
     /**
      * Constructs a pass-through operation from a set of properties.
@@ -106,7 +109,7 @@
     public DefaultPassThroughOperation(final Map<String,?>            properties,
                                        final CoordinateReferenceSystem sourceCRS,
                                        final CoordinateReferenceSystem targetCRS,
-                                       final CoordinateOperation       operation,
+                                       final SingleOperation           operation,
                                        final int firstAffectedCoordinate,
                                        final int numTrailingCoordinates)
     {
@@ -166,15 +169,43 @@
     }
 
     /**
+     * @deprecated May be removed in GeoAPI 4.0 since it does not apply to pass-through operations.
+     *
+     * @return {@code null}.
+     */
+    @Override
+    @Deprecated
+    public OperationMethod getMethod() {
+        return null;
+    }
+
+    /**
+     * @deprecated May be removed in GeoAPI 4.0 since it does not apply to pass-through operations.
+     *
+     * @return {@code null}.
+     */
+    @Override
+    @Deprecated
+    public ParameterValueGroup getParameterValues() {
+        return null;
+    }
+
+    /**
      * Returns the operation to apply on the subset of a coordinate tuple.
      *
+     * <div class="warning"><b>Upcoming API change</b><br>
+     * This method is conformant to ISO 19111:2003. But the ISO 19111:2007 revision changed the type from
+     * {@code SingleOperation} to {@link CoordinateOperation}. This change may be applied in GeoAPI 4.0.
+     * This is necessary for supporting usage of {@code PassThroughOperation} with {@code ConcatenatedOperation}.
+     * </div>
+     *
      * @return the operation to apply on the subset of a coordinate tuple.
      *
      * @see PassThroughTransform#getSubTransform()
      */
     @Override
     @XmlElement(name = "coordOperation", required = true)
-    public CoordinateOperation getOperation() {
+    public SingleOperation getOperation() {
         return operation;
     }
 
@@ -310,7 +341,7 @@
      *
      * @see #getOperation()
      */
-    private void setOperation(final CoordinateOperation op) {
+    private void setOperation(final SingleOperation op) {
         if (operation == null) {
             operation = op;
         } else {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
index 8318030..0e3185c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
@@ -69,7 +69,7 @@
      */
     private static Class<?> type(SingleCRS crs) {
         while (crs instanceof GeneralDerivedCRS) {
-            crs = ((GeneralDerivedCRS) crs).getBaseCRS();
+            crs = (SingleCRS) ((GeneralDerivedCRS) crs).getBaseCRS();
         }
         return crs.getClass();
     }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
index 51e1e64..f525f8d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
@@ -47,6 +47,17 @@
     }
 
     /**
+     * Returns {@code true} if the given operation is a single operation but not a pass-through operation.
+     * In an older ISO 19111 model, {@link PassThroughOperation} extended {@link SingleOperation}, which
+     * was a problem for providing a value to the inherited {@link SingleOperation#getMethod()} method.
+     * This has been fixed in newer ISO 19111 model, but for safety with objects following the older model
+     * (e.g. GeoAPI 3.0) we are better to perform an explicit exclusion of {@link PassThroughOperation}.
+     */
+    static boolean isSingleOperation(final CoordinateOperation operation) {
+        return (operation instanceof SingleOperation) && !(operation instanceof PassThroughOperation);
+    }
+
+    /**
      * Returns a SIS implementation for the given coordinate operation.
      *
      * @see AbstractCoordinateOperation#castOrCopy(CoordinateOperation)
@@ -64,7 +75,7 @@
         if (object instanceof ConcatenatedOperation) {
             return DefaultConcatenatedOperation.castOrCopy((ConcatenatedOperation) object);
         }
-        if (object instanceof SingleOperation) {
+        if (isSingleOperation(object)) {
             return (object instanceof AbstractSingleOperation) ? (AbstractSingleOperation) object
                    : new AbstractSingleOperation((SingleOperation) object);
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 5d5925c..6766f5d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -1568,6 +1568,19 @@
     }
 
     /**
+     * There is no XML format for math transforms.
+     *
+     * @param  xml  math transform encoded in XML format.
+     * @throws FactoryException if the object creation failed.
+     */
+    @Override
+    @Deprecated
+    public MathTransform createFromXML(String xml) throws FactoryException {
+        lastMethod.remove();
+        throw new FactoryException(Errors.format(Errors.Keys.UnsupportedOperation_1, "createFromXML"));
+    }
+
+    /**
      * Creates a math transform object from a
      * <a href="http://www.geoapi.org/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
      * Known Text</cite> (WKT)</a>.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
index ed1c8e9..31aacc3 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
@@ -23,8 +23,8 @@
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterValue;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.metadata.Identifier;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.apache.sis.measure.Range;
@@ -115,9 +115,9 @@
     {
         assertEquals(valueDomain, Parameters.getValueDomain(descriptor));
         assertEquals(valueDomain, Parameters.getValueDomain(new ParameterDescriptor<T>() {
-            @Override public Identifier               getName()          {return descriptor.getName();}
+            @Override public ReferenceIdentifier      getName()          {return descriptor.getName();}
             @Override public Collection<GenericName>  getAlias()         {return descriptor.getAlias();}
-            @Override public Set<Identifier>          getIdentifiers()   {return descriptor.getIdentifiers();}
+            @Override public Set<ReferenceIdentifier> getIdentifiers()   {return descriptor.getIdentifiers();}
             @Override public InternationalString      getRemarks()       {return descriptor.getRemarks();}
             @Override public InternationalString      getDescription()   {return descriptor.getDescription();}
             @Override public ParameterDirection       getDirection()     {return descriptor.getDirection();}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
index ad448a4..8061c26 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
@@ -23,7 +23,7 @@
 import java.util.Locale;
 import java.util.Collections;
 import org.opengis.test.Validators;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.referencing.datum.AbstractDatum;
 import org.apache.sis.internal.jaxb.referencing.Code;
 import org.apache.sis.internal.jaxb.Context;
@@ -56,10 +56,10 @@
      *
      * @param  identifiers  the value for the {@code "identifiers"} property.
      */
-    private static Map<String,Object> properties(final Set<Identifier> identifiers) {
+    private static Map<String,Object> properties(final Set<ReferenceIdentifier> identifiers) {
         final Map<String,Object> properties = new HashMap<>(8);
         assertNull(properties.put("name",       "GRS 1980"));
-        assertNull(properties.put("identifiers", identifiers.toArray(new Identifier[identifiers.size()])));
+        assertNull(properties.put("identifiers", identifiers.toArray(new ReferenceIdentifier[identifiers.size()])));
         assertNull(properties.put("codespace",  "EPSG"));
         assertNull(properties.put("version",    "8.3"));
         assertNull(properties.put("alias",      "International 1979"));
@@ -76,11 +76,11 @@
      * @param  gmlID        the expected value of {@link AbstractIdentifiedObject#getID()}.
      * @return the value of {@link AbstractIdentifiedObject#getIdentifier()}.
      */
-    private static Identifier validate(final AbstractIdentifiedObject object,
-            final Set<Identifier> identifiers, final String gmlID)
+    private static ReferenceIdentifier validate(final AbstractIdentifiedObject object,
+            final Set<ReferenceIdentifier> identifiers, final String gmlID)
     {
         Validators.validate(object);
-        final Identifier name = object.getName();
+        final ReferenceIdentifier name = object.getName();
         assertEquals("name",        "GRS 1980",                      name.getCode());
         assertEquals("codespace",   "EPSG",                          name.getCodeSpace());
         assertEquals("version",     "8.3",                           name.getVersion());
@@ -133,9 +133,9 @@
      */
     @Test
     public void testWithoutIdentifier() {
-        final Set<Identifier>          identifiers = Collections.emptySet();
+        final Set<ReferenceIdentifier> identifiers = Collections.emptySet();
         final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
-        final Identifier               gmlId       = validate(object, identifiers, "GRS1980");
+        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "GRS1980");
         assertNull("gmlId", gmlId);
     }
 
@@ -152,10 +152,10 @@
     @Test
     @DependsOnMethod("testWithoutIdentifier")
     public void testWithSingleIdentifier() {
-        final Identifier               identifier  = new ImmutableIdentifier(null, "EPSG", "7019");
-        final Set<Identifier>          identifiers = Collections.singleton(identifier);
+        final ReferenceIdentifier      identifier  = new ImmutableIdentifier(null, "EPSG", "7019");
+        final Set<ReferenceIdentifier> identifiers = Collections.singleton(identifier);
         final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
-        final Identifier               gmlId       = validate(object, identifiers, "epsg-7019");
+        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "epsg-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -169,11 +169,11 @@
     @Test
     @DependsOnMethod("testWithSingleIdentifier")
     public void testWithManyIdentifiers() {
-        final Set<Identifier> identifiers = new LinkedHashSet<>(4);
+        final Set<ReferenceIdentifier> identifiers = new LinkedHashSet<>(4);
         assertTrue(identifiers.add(new NamedIdentifier(EPSG, "7019")));
         assertTrue(identifiers.add(new NamedIdentifier(EPSG, "IgnoreMe")));
         final AbstractIdentifiedObject object = new AbstractIdentifiedObject(properties(identifiers));
-        final Identifier gmlId  = validate(object, identifiers, "epsg-7019");
+        final ReferenceIdentifier      gmlId  = validate(object, identifiers, "epsg-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -187,10 +187,10 @@
     @Test
     @DependsOnMethod("testWithManyIdentifiers")
     public void testAsSubtype() {
-        final Identifier               identifier  = new NamedIdentifier(EPSG, "7019");
-        final Set<Identifier>          identifiers = Collections.singleton(identifier);
+        final ReferenceIdentifier      identifier  = new NamedIdentifier(EPSG, "7019");
+        final Set<ReferenceIdentifier> identifiers = Collections.singleton(identifier);
         final AbstractIdentifiedObject object      = new AbstractDatum(properties(identifiers));
-        final Identifier               gmlId       = validate(object, identifiers, "epsg-datum-7019");
+        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "epsg-datum-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -234,7 +234,7 @@
     @Test
     @DependsOnMethod("testWithoutIdentifier")
     public void testSerialization() {
-        final Set<Identifier>     identifiers = Collections.emptySet();
+        final Set<ReferenceIdentifier> identifiers = Collections.emptySet();
         final AbstractIdentifiedObject object = new AbstractIdentifiedObject(properties(identifiers));
         final AbstractIdentifiedObject actual = assertSerializedEquals(object);
         assertNotSame(object, actual);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
index 221a5c0..3663c1f 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/epsg/package.html
@@ -131,7 +131,7 @@
 mvn clean install
 export CLASSPATH=~/.m2/repository/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar
 export CLASSPATH=$PWD/core/sis-metadata/target/test-classes:$CLASSPATH
-export CLASSPATH=$PWD/target/binaries/sis-referencing-2.0-SNAPSHOT.jar:$CLASSPATH
+export CLASSPATH=$PWD/target/binaries/sis-referencing-1.x-SNAPSHOT.jar:$CLASSPATH
 export CLASSPATH=$PWD/core/sis-metadata/target/test-classes:$CLASSPATH
 export CLASSPATH=$PWD/core/sis-referencing/target/test-classes:$CLASSPATH
 cd <i>&lt;path to local copy of <a href="http://svn.apache.org/repos/asf/sis/data/non-free/">http://svn.apache.org/repos/asf/sis/data/non-free/</a>&gt;</i>
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
index 1d2e044..e0035b3 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
@@ -134,7 +134,7 @@
          * because this is what will be unmarshalled from the XML document.
          */
         @SuppressWarnings("deprecation")
-        final DefaultResponsibility author = new DefaultResponsibleParty(Role.AUTHOR);
+        final DefaultResponsibleParty author = new DefaultResponsibleParty(Role.AUTHOR);
         final Anchor country = new Anchor(URI.create("SDN:C320:2:FR"), "France"); // Non-public SIS class.
         {
             final DefaultOnlineResource online = new DefaultOnlineResource(URI.create("http://www.ifremer.fr/sismer/"));
@@ -146,7 +146,7 @@
                     new DefaultTelephone("+33 (0)2 xx.xx.xx.x4", TelephoneType.FACSIMILE)
             ));
             final DefaultAddress address = new DefaultAddress();
-            address.setDeliveryPoints(singleton(new SimpleInternationalString("Brest institute")));
+            address.setDeliveryPoints(singleton("Brest institute"));
             address.setCity(new SimpleInternationalString("Plouzane"));
             address.setPostalCode("29280");
             address.setCountry(country);
@@ -166,7 +166,7 @@
                     new DefaultCitationDate(TestUtilities.date("1979-08-02 22:00:00"), DateType.CREATION)));
             {
                 @SuppressWarnings("deprecation")
-                final DefaultResponsibility originator = new DefaultResponsibleParty(Role.ORIGINATOR);
+                final DefaultResponsibleParty originator = new DefaultResponsibleParty(Role.ORIGINATOR);
                 final DefaultOnlineResource online = new DefaultOnlineResource(URI.create("http://www.com.univ-mrs.fr/LOB/"));
                 online.setProtocol("http");
                 final DefaultContact contact = new DefaultContact(online);
@@ -175,7 +175,7 @@
                         new DefaultTelephone("+33 (0)4 xx.xx.xx.x8", TelephoneType.FACSIMILE)
                 ));
                 final DefaultAddress address = new DefaultAddress();
-                address.setDeliveryPoints(singleton(new SimpleInternationalString("Oceanology institute")));
+                address.setDeliveryPoints(singleton("Oceanology institute"));
                 address.setCity(new SimpleInternationalString("Marseille"));
                 address.setPostalCode("13288");
                 address.setCountry(country);
@@ -190,7 +190,7 @@
                     TopicCategory.OCEANS);                                      // Topic category
             {
                 @SuppressWarnings("deprecation")
-                final DefaultResponsibility custodian = new DefaultResponsibleParty(author);
+                final DefaultResponsibleParty custodian = new DefaultResponsibleParty((DefaultResponsibility) author);
                 custodian.setRole(Role.CUSTODIAN);
                 identification.setPointOfContacts(singleton(custodian));
             }
@@ -312,7 +312,7 @@
                     Datatype.CODE_LIST,                                             // Data type
                     "SeaDataNet",                                                   // Parent entity
                     "For testing only",                                             // Rule
-                    NilReason.MISSING.createNilObject(Responsibility.class))));     // Source
+                    NilReason.MISSING.createNilObject(ResponsibleParty.class))));   // Source
             metadata.setMetadataExtensionInfo(singleton(extensionInfo));
         }
         /*
@@ -320,7 +320,7 @@
          */
         {
             @SuppressWarnings("deprecation")
-            final DefaultResponsibility distributor = new DefaultResponsibleParty(author);
+            final DefaultResponsibleParty distributor = new DefaultResponsibleParty((DefaultResponsibility) author);
             final DefaultDistribution distributionInfo = new DefaultDistribution();
             distributor.setRole(Role.DISTRIBUTOR);
             distributionInfo.setDistributors(singleton(new DefaultDistributor(distributor)));
@@ -340,7 +340,7 @@
             onlines.setProtocol("ftp");
             transfer.setOnLines(singleton(onlines));
             distributionInfo.setTransferOptions(singleton(transfer));
-            metadata.setDistributionInfo(singleton(distributionInfo));
+            metadata.setDistributionInfo(distributionInfo);
         }
         return metadata;
     }
diff --git a/core/sis-utility/pom.xml b/core/sis-utility/pom.xml
index 95590b6..7af5fa4 100644
--- a/core/sis-utility/pom.xml
+++ b/core/sis-utility/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>core</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java b/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
index 5b90bf3..8235270 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
@@ -112,14 +112,14 @@
      *
      * @see org.apache.sis.util.Version
      */
-    public static final int MAJOR_VERSION = 2;
+    public static final int MAJOR_VERSION = 1;
 
     /**
      * The minor version number of all Apache SIS modules.
      *
      * @see org.apache.sis.util.Version
      */
-    public static final int MINOR_VERSION = 0;
+    public static final int MINOR_VERSION = 9;
 
     /**
      * The prefix of all classnames in Apache SIS, including a trailing dot.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/temporal/Primitive.java b/core/sis-utility/src/main/java/org/apache/sis/internal/temporal/Primitive.java
index 412c704..20c6100 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/temporal/Primitive.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/temporal/Primitive.java
@@ -16,11 +16,11 @@
  */
 package org.apache.sis.internal.temporal;
 
-import org.opengis.metadata.Identifier;
 import org.opengis.temporal.Duration;
 import org.opengis.temporal.RelativePosition;
 import org.opengis.temporal.TemporalGeometricPrimitive;
 import org.opengis.temporal.TemporalPrimitive;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -32,7 +32,7 @@
  * @since   1.2
  * @module
  */
-class Primitive implements TemporalGeometricPrimitive, Identifier {
+class Primitive implements TemporalGeometricPrimitive, ReferenceIdentifier {
     /**
      * For sub-class constructors.
      */
@@ -44,7 +44,7 @@
      * This field is inherited from ISO 19111 {@code IdentifiedObject} and is in principle mandatory.
      */
     @Override
-    public final Identifier getName() {
+    public final ReferenceIdentifier getName() {
         return this;
     }
 
diff --git a/ide-project/NetBeans/nbproject/build-impl.xml b/ide-project/NetBeans/nbproject/build-impl.xml
index 26f5723..d0134b8 100644
--- a/ide-project/NetBeans/nbproject/build-impl.xml
+++ b/ide-project/NetBeans/nbproject/build-impl.xml
@@ -19,7 +19,7 @@
   - cleanup
 
         -->
-<project xmlns:if="ant:if" xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" xmlns:unless="ant:unless" basedir=".." default="default" name="Apache_SIS_on_GeoAPI_4.0-impl">
+<project xmlns:if="ant:if" xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" xmlns:unless="ant:unless" basedir=".." default="default" name="Apache_SIS_on_GeoAPI_3.1-impl">
     <fail message="Please build using Ant 1.8.0 or higher.">
         <condition>
             <not>
@@ -783,7 +783,7 @@
                     </fileset>
                 </union>
                 <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
-                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Apache_SIS_on_GeoAPI_4.0" testname="TestNG tests" workingDir="${work.dir}">
+                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Apache_SIS_on_GeoAPI_3.1" testname="TestNG tests" workingDir="${work.dir}">
                     <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
                     <propertyset>
                         <propertyref prefix="test-sys-prop."/>
@@ -880,7 +880,7 @@
                 <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
                     <isset property="test.method"/>
                 </condition>
-                <condition else="-suitename Apache_SIS_on_GeoAPI_4.0 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                <condition else="-suitename Apache_SIS_on_GeoAPI_3.1 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
                     <matches pattern=".*\.xml" string="@{testClass}"/>
                 </condition>
                 <delete dir="${build.test.results.dir}" quiet="true"/>
@@ -1221,7 +1221,7 @@
         <delete file="${built-jar.properties}" quiet="true"/>
     </target>
     <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
-        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 4.0 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.1 was already built"/>
     </target>
     <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -1231,15 +1231,6 @@
         <propertyfile file="${built-jar.properties}">
             <entry key="${basedir}" value=""/>
         </propertyfile>
-        <antcall target="-maybe-call-dep">
-            <param name="call.built.properties" value="${built-jar.properties}"/>
-            <param location="${project.GeoAPI}" name="call.subproject"/>
-            <param location="${project.GeoAPI}/build.xml" name="call.script"/>
-            <param name="call.target" value="jar"/>
-            <param name="transfer.built-jar.properties" value="${built-jar.properties}"/>
-            <param name="transfer.not.archive.disabled" value="true"/>
-            <param name="transfer.do.jlink" value="false"/>
-        </antcall>
     </target>
     <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
     <target depends="init" name="-check-automatic-build">
@@ -2059,7 +2050,7 @@
         <delete file="${built-clean.properties}" quiet="true"/>
     </target>
     <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
-        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 4.0 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.1 was already built"/>
     </target>
     <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -2069,15 +2060,6 @@
         <propertyfile file="${built-clean.properties}">
             <entry key="${basedir}" value=""/>
         </propertyfile>
-        <antcall target="-maybe-call-dep">
-            <param name="call.built.properties" value="${built-clean.properties}"/>
-            <param location="${project.GeoAPI}" name="call.subproject"/>
-            <param location="${project.GeoAPI}/build.xml" name="call.script"/>
-            <param name="call.target" value="clean"/>
-            <param name="transfer.built-clean.properties" value="${built-clean.properties}"/>
-            <param name="transfer.not.archive.disabled" value="true"/>
-            <param name="transfer.do.jlink" value="false"/>
-        </antcall>
     </target>
     <target depends="init" name="-do-clean">
         <delete dir="${build.dir}"/>
diff --git a/ide-project/NetBeans/nbproject/genfiles.properties b/ide-project/NetBeans/nbproject/genfiles.properties
index fde32dd..f00261f 100644
--- a/ide-project/NetBeans/nbproject/genfiles.properties
+++ b/ide-project/NetBeans/nbproject/genfiles.properties
@@ -3,6 +3,6 @@
 build.xml.data.CRC32=58e6b21c
 build.xml.script.CRC32=462eaba0
 build.xml.stylesheet.CRC32=28e38971@1.53.1.46
-nbproject/build-impl.xml.data.CRC32=f706d4ab
-nbproject/build-impl.xml.script.CRC32=6b1e829a
+nbproject/build-impl.xml.data.CRC32=4e7b2ef2
+nbproject/build-impl.xml.script.CRC32=7ab9bfcf
 nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.101.0.48
diff --git a/ide-project/NetBeans/nbproject/project.properties b/ide-project/NetBeans/nbproject/project.properties
index 75deaef..438b91d 100644
--- a/ide-project/NetBeans/nbproject/project.properties
+++ b/ide-project/NetBeans/nbproject/project.properties
@@ -88,17 +88,11 @@
 test.jpn-profile.dir = ${project.root}/profiles/sis-japan-profile/src/test/java
 
 #
-# Dependencies on other NetBeans projects. The path is relative to the "NetBeans" parent directory.
-# If a different path is desired, copy that line in the "private/private.properties" file and edit
-# its value there.
-#
-project.GeoAPI       = ../../../../GeoAPI/master/ide-project/NetBeans
-
-#
 # Version numbers for all dependencies.
 # Those dependencies must exist in the local Maven repository.
 # Those numbers should match the ones declared in the pom.xml files.
 #
+geoapi.version       = 3.1-SNAPSHOT
 jsr363.version       = 1.0
 jaxb.version         = 2.3.3
 jaxb.runtime         = 2.3.6
@@ -133,7 +127,7 @@
 maven.repository   = ${user.home}/.m2/repository
 endorsed.classpath =
 javac.classpath=\
-    ${project.GeoAPI}/dist/geoapi.jar:\
+    ${maven.repository}/org/opengis/geoapi-pending/${geoapi.version}/geoapi-pending-${geoapi.version}.jar:\
     ${maven.repository}/javax/measure/unit-api/${jsr363.version}/unit-api-${jsr363.version}.jar:\
     ${maven.repository}/jakarta/xml/bind/jakarta.xml.bind-api/${jaxb.version}/jakarta.xml.bind-api-${jaxb.version}.jar:\
     ${maven.repository}/com/esri/geometry/esri-geometry-api/${esri.api.version}/esri-geometry-api-${esri.api.version}.jar:\
@@ -148,6 +142,7 @@
     ${javac.classpath}
 javac.test.classpath=\
     ${javac.classpath}:\
+    ${maven.repository}/org/opengis/geoapi-conformance/${geoapi.version}/geoapi-conformance-${geoapi.version}.jar:\
     ${maven.repository}/org/apache/derby/derby/${derby.version}/derby-${derby.version}.jar:\
     ${maven.repository}/org/hsqldb/hsqldb/${hsqldb.version}/hsqldb-${hsqldb.version}.jar:\
     ${maven.repository}/com/h2database/h2/${h2.version}/h2-${h2.version}.jar:\
@@ -155,7 +150,6 @@
     ${maven.repository}/net/sf/geographiclib/GeographicLib-Java/${geographlib.version}/GeographicLib-Java-${geographlib.version}.jar:\
     ${maven.repository}/junit/junit/${junit.version}/junit-${junit.version}.jar:\
     ${maven.repository}/org/hamcrest/hamcrest-core/${hamcrest.version}/hamcrest-core-${hamcrest.version}.jar:\
-    ${project.GeoAPI}/dist/geoapi-tests.jar:\
     ${build.classes.dir}
 javac.test.processorpath=\
     ${javac.test.classpath}
diff --git a/ide-project/NetBeans/nbproject/project.xml b/ide-project/NetBeans/nbproject/project.xml
index e247d6f..69a414c 100644
--- a/ide-project/NetBeans/nbproject/project.xml
+++ b/ide-project/NetBeans/nbproject/project.xml
@@ -21,7 +21,7 @@
     <type>org.netbeans.modules.java.j2seproject</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
-            <name>Apache SIS on GeoAPI 4.0</name>
+            <name>Apache SIS on GeoAPI 3.1</name>
             <source-roots>
                 <root id="src.local-src.dir" name="Local sources (unversioned)"/>
                 <root id="src.javafx.dir" name="JavaFX application"/>
@@ -63,16 +63,6 @@
                 <root id="test.jpn-profile.dir" name="Test Japanese profile"/>
             </test-roots>
         </data>
-        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
-            <reference>
-                <foreign-project>GeoAPI</foreign-project>
-                <artifact-type>jar</artifact-type>
-                <script>build.xml</script>
-                <target>jar</target>
-                <clean-target>clean</clean-target>
-                <id>jar</id>
-            </reference>
-        </references>
         <spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
             <word>accessor</word>
             <word>antimeridian</word>
diff --git a/pom.xml b/pom.xml
index e6b7183..39d7e26 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,7 +50,7 @@
        ============================================================== -->
   <groupId>org.apache.sis</groupId>
   <artifactId>parent</artifactId>
-  <version>2.0-SNAPSHOT</version>
+  <version>1.x-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>Apache SIS</name>
@@ -558,7 +558,7 @@
     <sis.plugin.version>${project.version}</sis.plugin.version>
     <sis.non-free.version>1.2</sis.non-free.version>                <!-- Used only if "non-free" profile is activated. -->
     <javafx.version>18.0.1</javafx.version>                         <!-- Used only if "javafx" profile is activated. -->
-    <geoapi.version>4.0-SNAPSHOT</geoapi.version>
+    <geoapi.version>3.1-SNAPSHOT</geoapi.version>
   </properties>
 
   <profiles>
diff --git a/profiles/pom.xml b/profiles/pom.xml
index 610c412..799b04f 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/profiles/sis-french-profile/pom.xml b/profiles/sis-french-profile/pom.xml
index d4c8b2f..1c87162 100644
--- a/profiles/sis-french-profile/pom.xml
+++ b/profiles/sis-french-profile/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>profiles</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
index b65a2f4..56f6759 100644
--- a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
+++ b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
@@ -18,8 +18,8 @@
 
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
 import org.apache.sis.util.ComparisonMode;
 
@@ -71,7 +71,7 @@
      *
      * @param  identifier  the reference system identifier.
      */
-    public DirectReferenceSystem(final Identifier identifier) {
+    public DirectReferenceSystem(final ReferenceIdentifier identifier) {
         super(identifier);
     }
 
diff --git a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
index a649347..17f6ba5 100644
--- a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
+++ b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
@@ -18,8 +18,8 @@
 
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
 import org.apache.sis.util.ComparisonMode;
 
@@ -71,7 +71,7 @@
      *
      * @param  identifier  the reference system identifier.
      */
-    public IndirectReferenceSystem(final Identifier identifier) {
+    public IndirectReferenceSystem(final ReferenceIdentifier identifier) {
         super(identifier);
     }
 
diff --git a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
index e0ca6e1..41e30ea 100644
--- a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
+++ b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
@@ -18,12 +18,12 @@
 
 import java.util.Collection;
 import javax.xml.bind.JAXBException;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
+import org.apache.sis.internal.jaxb.metadata.replace.RS_Identifier;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.xml.TestCase;
@@ -58,12 +58,12 @@
     private static DefaultMetadata createMetadata(final boolean legacy) {
         final DefaultMetadata metadata = new DefaultMetadata();
         final DefaultCitation citation = new DefaultCitation("EPSG Geodetic Parameter Dataset");
-        Collection<Responsibility> r = HardCodedCitations.EPSG.getCitedResponsibleParties();
+        Collection<ResponsibleParty> r = HardCodedCitations.EPSG.getCitedResponsibleParties();
         if (legacy) {
             r = singleton(new DefaultResponsibleParty(TestUtilities.getSingleton(r)));
         }
         citation.setCitedResponsibleParties(r);
-        final DirectReferenceSystem refSys = new DirectReferenceSystem(new DefaultIdentifier(citation, "4326"));
+        final DirectReferenceSystem refSys = new DirectReferenceSystem(new RS_Identifier(citation, "4326"));
         metadata.setReferenceSystemInfo(singleton(refSys));
         return metadata;
     }
diff --git a/profiles/sis-french-profile/src/test/java/org/apache/sis/profile/france/FrenchProfileTest.java b/profiles/sis-french-profile/src/test/java/org/apache/sis/profile/france/FrenchProfileTest.java
index 90a5d6e..773f452 100644
--- a/profiles/sis-french-profile/src/test/java/org/apache/sis/profile/france/FrenchProfileTest.java
+++ b/profiles/sis-french-profile/src/test/java/org/apache/sis/profile/france/FrenchProfileTest.java
@@ -26,7 +26,7 @@
 import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
 import org.apache.sis.internal.profile.fra.IndirectReferenceSystem;
 import org.apache.sis.internal.profile.fra.DirectReferenceSystem;
-import org.apache.sis.metadata.iso.DefaultIdentifier;
+import org.apache.sis.internal.jaxb.metadata.replace.RS_Identifier;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -77,7 +77,7 @@
     public void testReferenceSystemToAFNOR() {
         ReferenceSystem std, fra;
 
-        std = new ReferenceSystemMetadata(new DefaultIdentifier("EPSG", "4326", null));
+        std = new ReferenceSystemMetadata(new RS_Identifier("EPSG", "4326", null));
         fra = FrenchProfile.toAFNOR(std, false);
         assertInstanceOf("Expected AFNOR instance.", DirectReferenceSystem.class, fra);
         assertSame("Already an AFNOR instance.", fra, FrenchProfile.toAFNOR(fra));
diff --git a/profiles/sis-japan-profile/pom.xml b/profiles/sis-japan-profile/pom.xml
index b131230..af37c45 100644
--- a/profiles/sis-japan-profile/pom.xml
+++ b/profiles/sis-japan-profile/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>profiles</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/pom.xml b/storage/pom.xml
index 1172482..b2b44ab 100644
--- a/storage/pom.xml
+++ b/storage/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-earth-observation/pom.xml b/storage/sis-earth-observation/pom.xml
index a3c9b82..551d818 100644
--- a/storage/sis-earth-observation/pom.xml
+++ b/storage/sis-earth-observation/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-geotiff/pom.xml b/storage/sis-geotiff/pom.xml
index 9453689..7a04cee 100644
--- a/storage/sis-geotiff/pom.xml
+++ b/storage/sis-geotiff/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-netcdf/pom.xml b/storage/sis-netcdf/pom.xml
index c6e6440..8f79efc 100644
--- a/storage/sis-netcdf/pom.xml
+++ b/storage/sis-netcdf/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index d499618..d797390 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -174,7 +174,7 @@
      * An object very similar is used as the creator. The point of contact and the creator
      * are often identical except for their role attribute.
      */
-    private transient Responsibility pointOfContact;
+    private transient ResponsibleParty pointOfContact;
 
     /**
      * The vertical coordinate reference system to be given to the object created by {@link #addExtent()}.
@@ -438,7 +438,7 @@
      * @see AttributeNames#CONTRIBUTOR
      * @see AttributeNames#PUBLISHER
      */
-    private Responsibility createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
+    private ResponsibleParty createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
         String individualName   = stringValue(keys.NAME);
         String organisationName = stringValue(keys.INSTITUTION);
         final String email      = stringValue(keys.EMAIL);
@@ -470,7 +470,7 @@
          * Verify if we can share the existing `pointOfContact` instance. This is often the case in practice.
          * If we can not share the whole existing instance, we usually can share parts of it like the address.
          */
-        Responsibility responsibility = pointOfContact;
+        ResponsibleParty responsibility = pointOfContact;
         Contact        contact        = null;
         Address        address        = null;
         OnlineResource resource       = null;
@@ -523,7 +523,8 @@
                 if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (Individual) party, null);
                 if (party            == null) party = isOrganisation(keys) ? new DefaultOrganisation() : new DefaultIndividual();
                 if (contact          != null) party.setContactInfo(singleton(contact));
-                responsibility = new DefaultResponsibility(role, null, party);
+                responsibility = new DefaultResponsibleParty(role);
+                ((DefaultResponsibleParty) responsibility).setParties(singleton(party));
             }
         }
         return responsibility;
@@ -574,7 +575,7 @@
          */
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final Responsibility party = createResponsibleParty(CREATOR, true);
+            final ResponsibleParty party = createResponsibleParty(CREATOR, true);
             if (party != pointOfContact) {
                 addPointOfContact(party, Scope.RESOURCE);
                 if (pointOfContact == null) {
@@ -595,11 +596,11 @@
         Set<InternationalString> publisher = null;
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final Responsibility contributor = createResponsibleParty(CONTRIBUTOR, false);
+            final ResponsibleParty contributor = createResponsibleParty(CONTRIBUTOR, false);
             if (contributor != pointOfContact) {
                 addCitedResponsibleParty(contributor, null);
             }
-            final Responsibility r = createResponsibleParty(PUBLISHER, false);
+            final ResponsibleParty r = createResponsibleParty(PUBLISHER, false);
             if (r != null) {
                 addDistributor(r);
                 for (final Party party : r.getParties()) {
@@ -629,7 +630,7 @@
             for (final String keyword : split(stringValue(ACCESS_CONSTRAINT))) {
                 addAccessConstraint(forCodeName(Restriction.class, keyword));
             }
-            addTopicCategory(forEnumName(TopicCategory.class, stringValue(TOPIC_CATEGORY)));
+            addTopicCategory(forCodeName(TopicCategory.class, stringValue(TOPIC_CATEGORY)));
             addSpatialRepresentation(forCodeName(SpatialRepresentationType.class, stringValue(DATA_TYPE)));
             if (!hasExtent) {
                 /*
diff --git a/storage/sis-shapefile/pom.xml b/storage/sis-shapefile/pom.xml
index f4db4ce..d74c5a9 100644
--- a/storage/sis-shapefile/pom.xml
+++ b/storage/sis-shapefile/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-sqlstore/pom.xml b/storage/sis-sqlstore/pom.xml
index cf1f6f3..83e67fa 100644
--- a/storage/sis-sqlstore/pom.xml
+++ b/storage/sis-sqlstore/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-storage/pom.xml b/storage/sis-storage/pom.xml
index f42705f..987e1b1 100644
--- a/storage/sis-storage/pom.xml
+++ b/storage/sis-storage/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
index dac0789..bee5a4d 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
@@ -243,16 +243,16 @@
     /**
      * Part of the responsible party of the {@linkplain #citation}, or {@code null} if none.
      */
-    private DefaultResponsibility responsibility;
+    private DefaultResponsibleParty responsibility;
 
     /**
      * Creates the responsibility object if it does not already exists, then returns it.
      *
      * @return the responsibility party (never {@code null}).
      */
-    private DefaultResponsibility responsibility() {
+    private DefaultResponsibleParty responsibility() {
         if (responsibility == null) {
-            responsibility = new DefaultResponsibility();
+            responsibility = new DefaultResponsibleParty();
         }
         return responsibility;
     }
@@ -688,7 +688,7 @@
      */
     public final void newDistribution() {
         if (distribution != null) {
-            addIfNotPresent(metadata().getDistributionInfo(), distribution);
+            metadata().setDistributionInfo(distribution);
             distribution = null;
         }
     }
@@ -1075,7 +1075,8 @@
         if (encoding != null) {
             // No need to use 'addIfNotPresent(…)' because Charset collection is a Set by default.
             if (scope != Scope.RESOURCE) metadata().getCharacterSets().add(encoding);
-            if (scope != Scope.METADATA) identification().getCharacterSets().add(encoding);
+            if (scope != Scope.METADATA) identification().getCharacterSets().add(
+                    Types.forCodeName(CharacterSet.class, encoding.toString(), true));
         }
     }
 
@@ -1299,10 +1300,9 @@
      * @param  page  the page, or {@code null} for no-operation.
      */
     public final void addPage(final CharSequence page) {
-        final InternationalString i18n = trim(page);
-        if (i18n != null) {
+        if (page != null) {
             final DefaultSeries series = series();
-            series.setPage(append(series.getPage(), i18n));
+            series.setPage(page.toString());
         }
     }
 
@@ -1380,7 +1380,8 @@
     public final void addOtherCitationDetails(final CharSequence details) {
         final InternationalString i18n = trim(details);
         if (i18n != null) {
-            addIfNotPresent(citation().getOtherCitationDetails(), i18n);
+            final DefaultCitation citation = citation();
+            citation.setOtherCitationDetails(append(citation.getOtherCitationDetails(), i18n));
         }
     }
 
@@ -1505,10 +1506,10 @@
      * @param  party  the individual or organization that is responsible, or {@code null} for no-operation.
      * @param  role   the role to set, or {@code null} for leaving it unchanged.
      */
-    public final void addCitedResponsibleParty(Responsibility party, final Role role) {
+    public final void addCitedResponsibleParty(ResponsibleParty party, final Role role) {
         if (party != null) {
             if (role != null && !role.equals(party.getRole())) {
-                party = new DefaultResponsibility(party);
+                party = new DefaultResponsibleParty(party);
                 ((DefaultResponsibility) party).setRole(role);
             }
             addIfNotPresent(citation().getCitedResponsibleParties(), party);
@@ -1528,7 +1529,7 @@
      * @param  contact  means of communication with party associated with the resource, or {@code null} for no-operation.
      * @param  scope    whether the contact applies to data, to metadata or to both.
      */
-    public final void addPointOfContact(final Responsibility contact, final Scope scope) {
+    public final void addPointOfContact(final ResponsibleParty contact, final Scope scope) {
         ArgumentChecks.ensureNonNull("scope", scope);
         if (contact != null) {
             if (scope != Scope.RESOURCE)     addIfNotPresent(metadata().getContacts(), contact);
@@ -1546,7 +1547,7 @@
      *
      * @param  distributor  the distributor, or {@code null} for no-operation.
      */
-    public final void addDistributor(final Responsibility distributor) {
+    public final void addDistributor(final ResponsibleParty distributor) {
         if (distributor != null) {
             addIfNotPresent(distribution().getDistributors(), new DefaultDistributor(distributor));
         }
@@ -1563,9 +1564,11 @@
      * @param  credit  recognition of those who contributed to the resource, or {@code null} for no-operation.
      */
     public final void addCredits(final CharSequence credit) {
-        final InternationalString i18n = trim(credit);
-        if (i18n != null) {
-            addIfNotPresent(identification().getCredits(), i18n);
+        if (credit != null) {
+            final String c = CharSequences.trimWhitespaces(credit).toString();
+            if (!c.isEmpty()) {
+                addIfNotPresent(identification().getCredits(), c);
+            }
         }
     }
 
@@ -1748,7 +1751,8 @@
                 buffer.setLength(i);
                 // Same limitation than MetadataBuilder.party().
                 final AbstractParty party = new AbstractParty(buffer, null);
-                final DefaultResponsibility r = new DefaultResponsibility(Role.OWNER, null, party);
+                final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.OWNER);
+                r.setParties(Collections.singleton(party));
                 c.setCitedResponsibleParties(Collections.singleton(r));
             }
             constraints.getReferences().add(c);
@@ -2921,7 +2925,7 @@
                 DefaultScope scope = new DefaultScope(level);
                 if (feature != null) {
                     final DefaultScopeDescription sd = new DefaultScopeDescription();
-                    sd.getFeatures().add(feature);
+                    sd.getFeatures().add(new org.apache.sis.metadata.iso.maintenance.LegacyFeatureType(feature));
                     scope.getLevelDescription().add(sd);
                 }
             }
@@ -3248,7 +3252,7 @@
             if (c != null) {
                 // Title, identifiers and series are assumed to not apply (see Javadoc).
                 final DefaultCitation citation = citation();
-                for (Responsibility r : c.getCitedResponsibleParties()) {
+                for (ResponsibleParty r : c.getCitedResponsibleParties()) {
                     addIfNotPresent(citation.getCitedResponsibleParties(), r);
                 }
                 for (OnlineResource r : c.getOnlineResources()) {
@@ -3289,9 +3293,10 @@
         for (AcquisitionInformation info : component.getAcquisitionInformation()) {
             addIfNotPresent(metadata.getAcquisitionInformation(), info);
         }
-        for (Distribution info : component.getDistributionInfo()) {
+        Distribution di = component.getDistributionInfo();
+        if (di != null) {
             // See Javadoc about why we copy only the distributors.
-            for (Distributor r : info.getDistributors()) {
+            for (Distributor r : di.getDistributors()) {
                 addIfNotPresent(distribution().getDistributors(), r);
             }
         }
diff --git a/storage/sis-xmlstore/pom.xml b/storage/sis-xmlstore/pom.xml
index 6bc38b6..54d50f5 100644
--- a/storage/sis-xmlstore/pom.xml
+++ b/storage/sis-xmlstore/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>storage</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>1.x-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
index 8832632..efe2fef 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
@@ -26,9 +26,7 @@
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.citation.OnlineResource;
-import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.util.iso.Types;
 
 
 /**
@@ -134,7 +132,7 @@
      */
     private Link(final OnlineResource r, final Locale locale) {
         uri  = r.getLinkage();
-        text = Types.toString(r.getName(), locale);
+        text = r.getName();
     }
 
     /**
@@ -165,8 +163,8 @@
      * @return name of the online resource.
      */
     @Override
-    public InternationalString getName() {
-        return (text != null) ? new SimpleInternationalString(text) : null;
+    public String getName() {
+        return text;
     }
 
     /**
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
index 32157d5..2a3be53 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
@@ -54,6 +54,7 @@
 import org.apache.sis.util.iso.Types;
 
 // Branch-dependent imports
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Responsibility;
 
 
@@ -318,10 +319,10 @@
      * @return means of communication with person(s) and organisations(s) associated with the resource.
      */
     @Override
-    public Collection<Responsibility> getPointOfContacts() {
+    public Collection<ResponsibleParty> getPointOfContacts() {
         if (creator != null) {
             final Person p = new Person(creator);
-            return (author != null) ? UnmodifiableArrayList.wrap(new Responsibility[] {p, author})
+            return (author != null) ? UnmodifiableArrayList.wrap(new ResponsibleParty[] {p, author})
                                     : Collections.singletonList(author);
         }
         return (author != null) ? Collections.singletonList(author) : Collections.emptyList();
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
index 3f9c8b4..e39ea73 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
@@ -16,8 +16,10 @@
  */
 package org.apache.sis.internal.storage.gpx;
 
+import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.Locale;
 import java.util.Objects;
 import javax.xml.bind.annotation.XmlElement;
@@ -26,6 +28,7 @@
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.Role;
+import org.opengis.metadata.citation.Telephone;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.util.iso.Types;
@@ -33,6 +36,7 @@
 // Branch-dependent imports
 import org.opengis.metadata.citation.Party;
 import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 
 
 /**
@@ -59,7 +63,7 @@
  * @since   0.8
  * @module
  */
-public final class Person implements Responsibility, Party, Contact, Address {
+public final class Person implements ResponsibleParty, Party, Contact, Address {
     /**
      * Name of person or organization.
      *
@@ -174,6 +178,37 @@
     }
 
     /**
+     * ISO 19115 metadata property not specified by GPX. Actually could be the {@link #name},
+     * but we have no way to know if the author is an individual or an organization.
+     *
+     * @return name of the organization, or {@code null} if none.
+     */
+    @Override
+    public InternationalString getOrganisationName() {
+        return null;
+    }
+
+    /**
+     * ISO 19115 metadata property not specified by GPX.
+     *
+     * @return position of the individual in the organization, or {@code null} if none.
+     */
+    @Override
+    public InternationalString getPositionName() {
+        return null;
+    }
+
+    /**
+     * ISO 19115 metadata property determined by the {@link #name} field.
+     *
+     * @return name of the party, or {@code null} if none.
+     */
+    @Override
+    public String getIndividualName() {
+        return name;
+    }
+
+    /**
      * ISO 19115 metadata property determined by the {@link #email} and {@link #link} fields.
      * Invoking this method is one of the steps in the path from the {@code Responsibility} root
      * to the {@link #getElectronicMailAddresses()} and {@link #getOnlineResources()} methods.
@@ -184,8 +219,28 @@
      * @see #getOnlineResources()
      */
     @Override
-    public Collection<? extends Contact> getContactInfo() {
-        return thisOrEmpty(email != null || link != null);
+    public Proxy getContactInfo() {        // Both Contact singleton and Collection<Contact>.
+        return new Proxy();
+    }
+
+    private final class Proxy extends AbstractSet<Contact> implements Contact {
+        @Override public int size() {
+            return (email != null || link != null) ? 1 : 0;
+        }
+
+        @Override public Iterator<Contact> iterator() {
+            return Collections.<Contact>singleton(Person.this).iterator();
+        }
+
+        @Override public Collection<? extends Telephone> getPhones()            {return Person.this.getPhones();}
+        @Override public Telephone                     getPhone()               {return Person.this.getPhone();}
+        @Override public Collection<? extends Address> getAddresses()           {return Person.this.getAddresses();}
+        @Override public Address                       getAddress()             {return Person.this.getAddress();}
+        @Override public Collection<OnlineResource>    getOnlineResources()     {return Person.this.getOnlineResources();}
+        @Override public OnlineResource                getOnlineResource()      {return Person.this.getOnlineResource();}
+        @Override public InternationalString           getHoursOfService()      {return Person.this.getHoursOfService();}
+        @Override public InternationalString           getContactInstructions() {return Person.this.getContactInstructions();}
+        @Override public InternationalString           getContactType()         {return Person.this.getContactType();}
     }