Merge the addition of AlbersEqualArea projection from the JDK6 branch.


git-svn-id: https://svn.apache.org/repos/asf/sis/trunk@1754384 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/application/pom.xml b/application/pom.xml
index 983073d..d7492f8 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-console/pom.xml b/application/sis-console/pom.xml
index f64b3ad..0a23324 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -111,21 +111,6 @@
       <version>${project.version}</version>
       <scope>runtime</scope>
     </dependency>
-
-    <!-- Test dependencies -->
-    <dependency>
-      <!-- For UCAR NetCDF -->
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-jdk14</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opengis.wrapper</groupId>
-      <artifactId>geoapi-netcdf</artifactId>
-      <version>${geoapi.version}</version>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.apache.sis.core</groupId>
       <artifactId>sis-metadata</artifactId>
diff --git a/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java b/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
index d6161cc..a6b17d7 100644
--- a/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
+++ b/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
@@ -38,6 +38,10 @@
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
 
+// Branch-dependent imports
+import org.apache.sis.metadata.iso.DefaultMetadata;
+import org.apache.sis.metadata.iso.DefaultIdentifier;
+
 
 /**
  * The "identifier" sub-command.
@@ -122,11 +126,11 @@
         }
         if (metadata != null) {
             final List<Row> rows;
-            if (metadata instanceof Metadata) {
+            if (metadata instanceof DefaultMetadata) {
                 rows = new ArrayList<Row>();
-                final Identifier id = ((Metadata) metadata).getMetadataIdentifier();
-                if (id != null) {
-                    CharSequence desc = id.getDescription();
+                final Identifier id = ((DefaultMetadata) metadata).getMetadataIdentifier();
+                if (id instanceof DefaultIdentifier) {
+                    CharSequence desc = ((DefaultIdentifier) id).getDescription();
                     if (desc != null && !files.isEmpty()) desc = files.get(0);
                     rows.add(new Row(State.VALID, IdentifiedObjects.toString(id), desc));
                 }
diff --git a/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java b/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
index 5a96cf8..7e4ad9c 100644
--- a/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
+++ b/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
@@ -17,10 +17,10 @@
 package org.apache.sis.console;
 
 import java.net.URL;
-import org.opengis.wrapper.netcdf.IOTestCase;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -42,9 +42,10 @@
      * @throws Exception if an error occurred while creating the command.
      */
     @Test
+    @Ignore("Requires GeoAPI 3.1")
     public void testNetCDF() throws Exception {
-        final URL url = IOTestCase.class.getResource(IOTestCase.NCEP);
-        assertNotNull(IOTestCase.NCEP, url);
+        final URL url = MetadataCommandTest.class.getResource("NCEP-SST.nc");
+        assertNotNull("NCEP-SST.nc", url);
         final MetadataCommand test = new MetadataCommand(0, CommandRunner.TEST, url.toString());
         test.run();
         verifyNetCDF("Metadata", test.outputBuffer.toString());
@@ -68,9 +69,10 @@
      * @throws Exception if an error occurred while creating the command.
      */
     @Test
+    @Ignore("Requires GeoAPI 3.1")
     @DependsOnMethod("testNetCDF")
     public void testFormatXML() throws Exception {
-        final URL url = IOTestCase.class.getResource(IOTestCase.NCEP);
+        final URL url = MetadataCommandTest.class.getResource("NCEP-SST.nc");
         final MetadataCommand test = new MetadataCommand(0, CommandRunner.TEST, url.toString(), "--format", "XML");
         test.run();
         verifyNetCDF("<?xml", test.outputBuffer.toString());
diff --git a/application/sis-javafx/pom.xml b/application/sis-javafx/pom.xml
index b2b9788..c434029 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/application/sis-openoffice/pom.xml b/application/sis-openoffice/pom.xml
index b8784a3..6ae1a40 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -88,7 +88,7 @@
   <dependencies>
     <dependency>
       <groupId>org.opengis</groupId>
-      <artifactId>geoapi-pending</artifactId>
+      <artifactId>geoapi</artifactId>
     </dependency>
     <dependency>
       <groupId>javax.measure</groupId>
diff --git a/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/ReferencingFunctionsTest.java b/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/ReferencingFunctionsTest.java
index 7bf6d04..3ccc179 100644
--- a/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/ReferencingFunctionsTest.java
+++ b/application/sis-openoffice/src/test/java/org/apache/sis/openoffice/ReferencingFunctionsTest.java
@@ -26,7 +26,7 @@
 import org.junit.Test;
 
 import static org.junit.Assert.*;
-import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
 
 
 /**
@@ -102,7 +102,7 @@
     public void testGetGeographicArea() {
         final double[][] bbox = instance.getGeographicArea("EPSG:32620");     // UTM zone 20
         assertEquals(2, bbox.length);
-        assumeFalse(Double.isNaN(bbox[0][0]));    // NaN if EPSG dataset is not installed.
+        assumeTrue(!Double.isNaN(bbox[0][0]));    // NaN if EPSG dataset is not installed.
         assertArrayEquals("Upper left corner",  new double[] {84, -66}, bbox[0], STRICT);
         assertArrayEquals("Lower right corner", new double[] { 0, -60}, bbox[1], STRICT);
     }
diff --git a/application/sis-webapp/pom.xml b/application/sis-webapp/pom.xml
index 8882dcc..7c69ea6 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.application</groupId>
diff --git a/core/pom.xml b/core/pom.xml
index 4b23e00..c241f8a 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -164,7 +164,7 @@
   <dependencies>
     <dependency>
       <groupId>org.opengis</groupId>
-      <artifactId>geoapi-pending</artifactId>
+      <artifactId>geoapi</artifactId>
     </dependency>
 
     <!-- Test dependencies -->
diff --git a/core/sis-build-helper/pom.xml b/core/sis-build-helper/pom.xml
index e7d457f..90fc724 100644
--- a/core/sis-build-helper/pom.xml
+++ b/core/sis-build-helper/pom.xml
@@ -29,7 +29,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
diff --git a/core/sis-feature/pom.xml b/core/sis-feature/pom.xml
index 9fa8dc1..2ae32b2 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
index 392cd85..ed0635f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
@@ -25,14 +25,6 @@
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.MultiValuedPropertyException;
-
 
 /**
  * An instance of an {@linkplain DefaultAssociationRole feature association role} containing the associated feature.
@@ -55,7 +47,7 @@
  * @see AbstractFeature
  * @see DefaultAssociationRole
  */
-public abstract class AbstractAssociation extends Field<Feature> implements FeatureAssociation, Cloneable, Serializable {
+public abstract class AbstractAssociation extends Field<AbstractFeature> implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -64,16 +56,16 @@
     /**
      * Information about the association.
      */
-    final FeatureAssociationRole role;
+    final DefaultAssociationRole role;
 
     /**
      * Creates a new association of the given role.
      *
      * @param role Information about the association.
      *
-     * @see #create(FeatureAssociationRole)
+     * @see #create(DefaultAssociationRole)
      */
-    protected AbstractAssociation(final FeatureAssociationRole role) {
+    protected AbstractAssociation(final DefaultAssociationRole role) {
         this.role = role;
     }
 
@@ -85,7 +77,7 @@
      *
      * @see DefaultAssociationRole#newInstance()
      */
-    public static AbstractAssociation create(final FeatureAssociationRole role) {
+    public static AbstractAssociation create(final DefaultAssociationRole role) {
         ArgumentChecks.ensureNonNull("role", role);
         return isSingleton(role.getMaximumOccurs())
                ? new SingletonAssociation(role)
@@ -99,16 +91,16 @@
      * @param  value The initial value (may be {@code null}).
      * @return The new association.
      */
-    static AbstractAssociation create(final FeatureAssociationRole role, final Object value) {
+    static AbstractAssociation create(final DefaultAssociationRole role, final Object value) {
         ArgumentChecks.ensureNonNull("role", role);
         return isSingleton(role.getMaximumOccurs())
-               ? new SingletonAssociation(role, (Feature) value)
+               ? new SingletonAssociation(role, (AbstractFeature) value)
                : new MultiValuedAssociation(role, value);
     }
 
     /**
      * Returns the name of this association as defined by its {@linkplain #getRole() role}.
-     * This convenience method delegates to {@link FeatureAssociationRole#getName()}.
+     * This convenience method delegates to {@link DefaultAssociationRole#getName()}.
      *
      * @return The association name specified by its role.
      */
@@ -120,10 +112,12 @@
     /**
      * Returns information about the association.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.AssociationRole}. This change is pending GeoAPI revision.</div>
+     *
      * @return Information about the association.
      */
-    @Override
-    public FeatureAssociationRole getRole() {
+    public DefaultAssociationRole getRole() {
         return role;
     }
 
@@ -132,13 +126,16 @@
      * the common case where the {@linkplain DefaultAssociationRole#getMaximumOccurs() maximum number} of
      * features is restricted to 1 or 0.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.Feature}. This change is pending GeoAPI revision.</div>
+     *
      * @return The associated feature (may be {@code null}).
-     * @throws MultiValuedPropertyException if this association contains more than one value.
+     * @throws IllegalStateException if this association contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract Feature getValue() throws MultiValuedPropertyException;
+    public abstract AbstractFeature getValue() throws IllegalStateException;
 
     /**
      * Returns all features, or an empty collection if none.
@@ -151,13 +148,16 @@
      * @return The features in a <cite>live</cite> collection.
      */
     @Override
-    public Collection<Feature> getValues() {
+    public Collection<AbstractFeature> getValues() {
         return super.getValues();
     }
 
     /**
      * Sets the associated feature.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the argument type may be changed
+     * to {@code org.opengis.feature.Feature}. This change is pending GeoAPI revision.</div>
+     *
      * <div class="section">Validation</div>
      * The amount of validation performed by this method is implementation dependent.
      * Usually, only the most basic constraints are verified. This is so for performance reasons
@@ -165,24 +165,24 @@
      * A more exhaustive verification can be performed by invoking the {@link #quality()} method.
      *
      * @param  value The new value, or {@code null}.
-     * @throws InvalidPropertyValueException If the given feature is not valid for this association.
+     * @throws IllegalArgumentException If the given feature is not valid for this association.
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
     @Override
-    public abstract void setValue(final Feature value) throws InvalidPropertyValueException;
+    public abstract void setValue(final AbstractFeature value) throws IllegalArgumentException;
 
     /**
      * Sets the features. All previous values are replaced by the given collection.
      *
      * <p>The default implementation ensures that the given collection contains at most one element,
-     * then delegates to {@link #setValue(Feature)}.</p>
+     * then delegates to {@link #setValue(AbstractFeature)}.</p>
      *
      * @param  values The new values.
-     * @throws InvalidPropertyValueException if the given collection contains too many elements.
+     * @throws IllegalArgumentException if the given collection contains too many elements.
      */
     @Override
-    public void setValues(final Collection<? extends Feature> values) throws InvalidPropertyValueException {
+    public void setValues(final Collection<? extends AbstractFeature> values) throws IllegalArgumentException {
         super.setValues(values);
     }
 
@@ -190,9 +190,9 @@
      * Ensures that storing a feature of the given type is valid for an association
      * expecting the given base type.
      */
-    final void ensureValid(final FeatureType base, final FeatureType type) {
+    final void ensureValid(final DefaultFeatureType base, final DefaultFeatureType type) {
         if (base != type && !DefaultFeatureType.maybeAssignableFrom(base, type)) {
-            throw new InvalidPropertyValueException(
+            throw new IllegalArgumentException(
                     Errors.format(Errors.Keys.IllegalArgumentClass_3, getName(), base.getName(), type.getName()));
         }
     }
@@ -228,7 +228,7 @@
     @Override
     public String toString() {
         final String pt = DefaultAssociationRole.getTitleProperty(role);
-        final Iterator<Feature> it = getValues().iterator();
+        final Iterator<AbstractFeature> it = getValues().iterator();
         return FieldType.toString("FeatureAssociation", role, DefaultAssociationRole.getValueTypeName(role), new Iterator<Object>() {
             @Override public boolean hasNext() {
                 return it.hasNext();
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
index dd77d77..975ce99 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
@@ -33,10 +33,6 @@
 import org.apache.sis.util.ArgumentChecks;
 
 // Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.MultiValuedPropertyException;
 import org.apache.sis.internal.jdk7.JDK7;
 
 
@@ -76,7 +72,7 @@
  * @see AbstractFeature
  * @see DefaultAttributeType
  */
-public abstract class AbstractAttribute<V> extends Field<V> implements Attribute<V>, Cloneable, Serializable {
+public abstract class AbstractAttribute<V> extends Field<V> implements Cloneable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -85,7 +81,7 @@
     /**
      * Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    final AttributeType<V> type;
+    final DefaultAttributeType<V> type;
 
     /**
      * Other attributes that describes this attribute, or {@code null} if not yet created.
@@ -100,16 +96,16 @@
      *
      * @see #characteristics()
      */
-    private transient Map<String,Attribute<?>> characteristics;
+    private transient Map<String,AbstractAttribute<?>> characteristics;
 
     /**
      * Creates a new attribute of the given type.
      *
      * @param type  information about the attribute (base Java class, domain of values, <i>etc.</i>).
      *
-     * @see #create(AttributeType)
+     * @see #create(DefaultAttributeType)
      */
-    protected AbstractAttribute(final AttributeType<V> type) {
+    protected AbstractAttribute(final DefaultAttributeType<V> type) {
         this.type = type;
     }
 
@@ -123,7 +119,7 @@
      *
      * @see DefaultAttributeType#newInstance()
      */
-    public static <V> AbstractAttribute<V> create(final AttributeType<V> type) {
+    public static <V> AbstractAttribute<V> create(final DefaultAttributeType<V> type) {
         ArgumentChecks.ensureNonNull("type", type);
         return isSingleton(type.getMaximumOccurs())
                ? new SingletonAttribute<V>(type)
@@ -139,7 +135,7 @@
      * @param  value  the initial value (may be {@code null}).
      * @return The new attribute.
      */
-    static <V> AbstractAttribute<V> create(final AttributeType<V> type, final Object value) {
+    static <V> AbstractAttribute<V> create(final DefaultAttributeType<V> type, final Object value) {
         ArgumentChecks.ensureNonNull("type", type);
         return isSingleton(type.getMaximumOccurs())
                ? new SingletonAttribute<V>(type, value)
@@ -154,9 +150,9 @@
      */
     private void writeObject(final ObjectOutputStream out) throws IOException {
         out.defaultWriteObject();
-        final Attribute<?>[] characterizedBy;
+        final AbstractAttribute<?>[] characterizedBy;
         if (characteristics instanceof CharacteristicMap) {
-            characterizedBy = characteristics.values().toArray(new Attribute<?>[characteristics.size()]);
+            characterizedBy = characteristics.values().toArray(new AbstractAttribute<?>[characteristics.size()]);
         } else {
             characterizedBy = null;
         }
@@ -173,7 +169,7 @@
     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
         in.defaultReadObject();
         try {
-            final Attribute<?>[] characterizedBy = (Attribute<?>[]) in.readObject();
+            final AbstractAttribute<?>[] characterizedBy = (AbstractAttribute<?>[]) in.readObject();
             if (characterizedBy != null) {
                 characteristics = newCharacteristicsMap();
                 characteristics.values().addAll(Arrays.asList(characterizedBy));
@@ -185,7 +181,7 @@
 
     /**
      * Returns the name of this attribute as defined by its {@linkplain #getType() type}.
-     * This convenience method delegates to {@link AttributeType#getName()}.
+     * This convenience method delegates to {@link DefaultAttributeType#getName()}.
      *
      * @return the attribute name specified by its type.
      */
@@ -197,10 +193,12 @@
     /**
      * Returns information about the attribute (base Java class, domain of values, <i>etc.</i>).
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.AttributeType}. This change is pending GeoAPI revision.</div>
+     *
      * @return information about the attribute.
      */
-    @Override
-    public AttributeType<V> getType() {
+    public DefaultAttributeType<V> getType() {
         return type;
     }
 
@@ -210,12 +208,12 @@
      * of attribute values is restricted to 1 or 0.
      *
      * @return the attribute value (may be {@code null}).
-     * @throws MultiValuedPropertyException if this attribute contains more than one value.
+     * @throws IllegalStateException if this attribute contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract V getValue() throws MultiValuedPropertyException;
+    public abstract V getValue() throws IllegalStateException;
 
     /**
      * Returns all attribute values, or an empty collection if none.
@@ -242,13 +240,13 @@
      * A more exhaustive verification can be performed by invoking the {@link #quality()} method.
      *
      * @param  value  the new value, or {@code null} for removing all values from this attribute.
-     * @throws InvalidPropertyValueException if this method verifies argument validity and the given value
+     * @throws IllegalArgumentException if this method verifies argument validity and the given value
      *         does not met the attribute constraints.
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
     @Override
-    public abstract void setValue(final V value) throws InvalidPropertyValueException;
+    public abstract void setValue(final V value) throws IllegalArgumentException;
 
     /**
      * Sets the attribute values. All previous values are replaced by the given collection.
@@ -257,10 +255,10 @@
      * then delegates to {@link #setValue(Object)}.</p>
      *
      * @param  values  the new values.
-     * @throws InvalidPropertyValueException if the given collection contains too many elements.
+     * @throws IllegalArgumentException if the given collection contains too many elements.
      */
     @Override
-    public void setValues(final Collection<? extends V> values) throws InvalidPropertyValueException {
+    public void setValues(final Collection<? extends V> values) throws IllegalArgumentException {
         super.setValues(values);
     }
 
@@ -339,9 +337,8 @@
      *
      * @see DefaultAttributeType#characteristics()
      */
-    @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public Map<String,Attribute<?>> characteristics() {
+    public Map<String,AbstractAttribute<?>> characteristics() {
         if (characteristics == null) {
             characteristics = newCharacteristicsMap();
         }
@@ -353,13 +350,13 @@
      * This method does not store the new map in the {@link #characteristics} field;
      * it is caller responsibility to do so if desired.
      */
-    private Map<String,Attribute<?>> newCharacteristicsMap() {
+    private Map<String,AbstractAttribute<?>> newCharacteristicsMap() {
         if (type instanceof DefaultAttributeType<?>) {
-            Map<String, AttributeType<?>> map = ((DefaultAttributeType<?>) type).characteristics();
+            Map<String, DefaultAttributeType<?>> map = type.characteristics();
             if (!map.isEmpty()) {
                 if (!(map instanceof CharacteristicTypeMap)) {
-                    final Collection<AttributeType<?>> types = map.values();
-                    map = CharacteristicTypeMap.create(type, types.toArray(new AttributeType<?>[types.size()]));
+                    final Collection<DefaultAttributeType<?>> types = map.values();
+                    map = CharacteristicTypeMap.create(type, types.toArray(new DefaultAttributeType<?>[types.size()]));
                 }
                 return new CharacteristicMap(this, (CharacteristicTypeMap) map);
             }
@@ -372,8 +369,8 @@
      * Contrarily to {@link #characteristics()}, this method does not create the map. This method
      * is suitable when then caller only wants to read the map and does not plan to write anything.
      */
-    final Map<String,Attribute<?>> characteristicsReadOnly() {
-        return (characteristics != null) ? characteristics : Collections.<String,Attribute<?>>emptyMap();
+    final Map<String,AbstractAttribute<?>> characteristicsReadOnly() {
+        return (characteristics != null) ? characteristics : Collections.<String,AbstractAttribute<?>>emptyMap();
     }
 
     /**
@@ -470,7 +467,7 @@
         if (characteristics != null && !characteristics.isEmpty()) {
             buffer.append(JDK7.lineSeparator());
             String separator = "└─ characteristics: ";
-            for (final Map.Entry<String,Attribute<?>> entry : characteristics.entrySet()) {
+            for (final Map.Entry<String,AbstractAttribute<?>> entry : characteristics.entrySet()) {
                 buffer.append(separator).append(entry.getKey()).append('=').append(entry.getValue().getValue());
                 separator = ", ";
             }
@@ -493,7 +490,7 @@
     @SuppressWarnings("unchecked")
     public AbstractAttribute<V> clone() throws CloneNotSupportedException {
         final AbstractAttribute<V> clone = (AbstractAttribute<V>) super.clone();
-        final Map<String,Attribute<?>> c = clone.characteristics;
+        final Map<String,AbstractAttribute<?>> c = clone.characteristics;
         if (c instanceof CharacteristicMap) {
             clone.characteristics = ((CharacteristicMap) c).clone();
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
index 93a000f..6b76825 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
@@ -28,19 +28,6 @@
 import org.apache.sis.util.CorruptedObjectException;
 import org.apache.sis.internal.util.CheckedArrayList;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.PropertyNotFoundException;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.Operation;
-
 
 /**
  * An instance of a {@linkplain DefaultFeatureType feature type} containing values for a real-world phenomena.
@@ -79,7 +66,7 @@
  *
  * @see DefaultFeatureType#newInstance()
  */
-public abstract class AbstractFeature implements Feature, Serializable {
+public abstract class AbstractFeature implements Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -88,7 +75,7 @@
     /**
      * Information about the feature (name, characteristics, <i>etc.</i>).
      */
-    final FeatureType type;
+    final DefaultFeatureType type;
 
     /**
      * Creates a new feature of the given type.
@@ -97,7 +84,7 @@
      *
      * @see DefaultFeatureType#newInstance()
      */
-    protected AbstractFeature(final FeatureType type) {
+    protected AbstractFeature(final DefaultFeatureType type) {
         ArgumentChecks.ensureNonNull("type", type);
         this.type = type;
     }
@@ -113,10 +100,12 @@
     /**
      * Returns information about the feature (name, characteristics, <i>etc.</i>).
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.FeatureType}. This change is pending GeoAPI revision.</div>
+     *
      * @return Information about the feature.
      */
-    @Override
-    public FeatureType getType() {
+    public DefaultFeatureType getType() {
         return type;
     }
 
@@ -126,19 +115,21 @@
      * method may return the result of {@linkplain AbstractOperation#apply executing} the operation
      * on this feature, at implementation choice.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.Property}. This change is pending GeoAPI revision.</div>
+     *
      * <div class="note"><b>Tip:</b> This method returns the property <em>instance</em>. If only the property
      * <em>value</em> is desired, then {@link #getPropertyValue(String)} is preferred since it gives to SIS a
      * chance to avoid the creation of {@link AbstractAttribute} or {@link AbstractAssociation} instances.</div>
      *
      * @param  name The property name.
      * @return The property of the given name (never {@code null}).
-     * @throws PropertyNotFoundException if the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException if the given argument is not a property name of this feature.
      *
      * @see #getPropertyValue(String)
      * @see DefaultFeatureType#getProperty(String)
      */
-    @Override
-    public abstract Property getProperty(final String name) throws PropertyNotFoundException;
+    public abstract Object getProperty(final String name) throws IllegalArgumentException;
 
     /**
      * Sets the property (attribute or feature association).
@@ -160,15 +151,17 @@
      * {@code FeatureAssociation} implementations in this feature. When default implementations are sufficient,
      * the {@link #setPropertyValue(String, Object)} method is preferred.</div>
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the argument may be changed
+     * to {@code org.opengis.feature.Property}. This change is pending GeoAPI revision.</div>
+     *
      * @param  property The property to set.
-     * @throws PropertyNotFoundException if the name of the given property is not a property name of this feature.
-     * @throws InvalidPropertyValueException if the value of the given property is not valid.
+     * @throws IllegalArgumentException if the name of the given property is not a property name of this feature.
+     * @throws IllegalArgumentException if the value of the given property is not valid.
      * @throws IllegalArgumentException if the property can not be set for another reason.
      *
      * @see #setPropertyValue(String, Object)
      */
-    @Override
-    public abstract void setProperty(final Property property) throws IllegalArgumentException;
+    public abstract void setProperty(final Object property) throws IllegalArgumentException;
 
     /**
      * Wraps the given value in a {@link Property} object. This method is invoked only by
@@ -180,11 +173,11 @@
      */
     @SuppressWarnings({"unchecked","rawtypes"})
     final Property createProperty(final String name, final Object value) {
-        final PropertyType pt = type.getProperty(name);
-        if (pt instanceof AttributeType<?>) {
-            return AbstractAttribute.create((AttributeType<?>) pt, value);
-        } else if (pt instanceof FeatureAssociationRole) {
-            return AbstractAssociation.create((FeatureAssociationRole) pt, value);
+        final AbstractIdentifiedType pt = type.getProperty(name);
+        if (pt instanceof DefaultAttributeType<?>) {
+            return AbstractAttribute.create((DefaultAttributeType<?>) pt, value);
+        } else if (pt instanceof DefaultAssociationRole) {
+            return AbstractAssociation.create((DefaultAssociationRole) pt, value);
         } else {
             // Should never happen, unless the user gave us some mutable FeatureType.
             throw new CorruptedObjectException(Errors.format(Errors.Keys.UnknownType_1, pt));
@@ -196,15 +189,15 @@
      *
      * @param  name The name of the property to create.
      * @return A {@code Property} of the given name.
-     * @throws PropertyNotFoundException if the given argument is not the name of an attribute or
+     * @throws IllegalArgumentException if the given argument is not the name of an attribute or
      *         feature association of this feature.
      */
-    final Property createProperty(final String name) throws PropertyNotFoundException {
-        final PropertyType pt = type.getProperty(name);
-        if (pt instanceof AttributeType<?>) {
-            return ((AttributeType<?>) pt).newInstance();
-        } else if (pt instanceof FeatureAssociationRole) {
-            return ((FeatureAssociationRole) pt).newInstance();
+    final Property createProperty(final String name) throws IllegalArgumentException {
+        final AbstractIdentifiedType pt = type.getProperty(name);
+        if (pt instanceof DefaultAttributeType<?>) {
+            return ((DefaultAttributeType<?>) pt).newInstance();
+        } else if (pt instanceof DefaultAssociationRole) {
+            return ((DefaultAssociationRole) pt).newInstance();
         } else {
             throw unsupportedPropertyType(pt.getName());
         }
@@ -213,29 +206,29 @@
     /**
      * Executes the parameterless operation of the given name and returns its result.
      */
-    final Property getOperationResult(final String name) {
+    final Object getOperationResult(final String name) {
         /*
          * The (Operation) cast below should never fail (unless the DefaultFeatureType in not really immutable,
          * which would be a contract violation) because all callers shall ensure that this method is invoked in
          * a context where the following assertion holds.
          */
-        assert DefaultFeatureType.OPERATION_INDEX.equals(((DefaultFeatureType) type).indices().get(name)) : name;
-        return ((Operation) type.getProperty(name)).apply(this, null);
+        assert DefaultFeatureType.OPERATION_INDEX.equals(type.indices().get(name)) : name;
+        return ((AbstractOperation) type.getProperty(name)).apply(this, null);
     }
 
     /**
      * Executes the parameterless operation of the given name and returns the value of its result.
      */
     final Object getOperationValue(final String name) {
-        final Operation operation = (Operation) type.getProperty(name);
+        final AbstractOperation operation = (AbstractOperation) type.getProperty(name);
         if (operation instanceof LinkOperation) {
             return getPropertyValue(((LinkOperation) operation).referentName);
         }
-        final Property result = operation.apply(this, null);
-        if (result instanceof Attribute<?>) {
-            return getAttributeValue((Attribute<?>) result);
-        } else if (result instanceof FeatureAssociation) {
-            return getAssociationValue((FeatureAssociation) result);
+        final Object result = operation.apply(this, null);
+        if (result instanceof AbstractAttribute<?>) {
+            return getAttributeValue((AbstractAttribute<?>) result);
+        } else if (result instanceof AbstractAssociation) {
+            return getAssociationValue((AbstractAssociation) result);
         } else {
             return null;
         }
@@ -245,13 +238,13 @@
      * Executes the parameterless operation of the given name and sets the value of its result.
      */
     final void setOperationValue(final String name, final Object value) {
-        final Operation operation = (Operation) type.getProperty(name);
+        final AbstractOperation operation = (AbstractOperation) type.getProperty(name);
         if (operation instanceof LinkOperation) {
             setPropertyValue(((LinkOperation) operation).referentName, value);
         } else {
-            final Property result = operation.apply(this, null);
-            if (result != null) {
-                setPropertyValue(result, value);
+            final Object result = operation.apply(this, null);
+            if (result instanceof Property) {
+                setPropertyValue((Property) result, value);
             } else {
                 throw new IllegalStateException(Errors.format(Errors.Keys.CanNotSetPropertyValue_1, name));
             }
@@ -264,14 +257,14 @@
      *
      * @param  name The name of the property for which to get the default value.
      * @return The default value for the {@code Property} of the given name.
-     * @throws PropertyNotFoundException if the given argument is not an attribute or association name of this feature.
+     * @throws IllegalArgumentException if the given argument is not an attribute or association name of this feature.
      */
-    final Object getDefaultValue(final String name) throws PropertyNotFoundException {
-        final PropertyType pt = type.getProperty(name);
-        if (pt instanceof AttributeType<?>) {
-            return getDefaultValue((AttributeType<?>) pt);
-        } else if (pt instanceof FeatureAssociationRole) {
-            final int maximumOccurs = ((FeatureAssociationRole) pt).getMaximumOccurs();
+    final Object getDefaultValue(final String name) throws IllegalArgumentException {
+        final AbstractIdentifiedType pt = type.getProperty(name);
+        if (pt instanceof DefaultAttributeType<?>) {
+            return getDefaultValue((DefaultAttributeType<?>) pt);
+        } else if (pt instanceof DefaultAssociationRole) {
+            final int maximumOccurs = ((DefaultAssociationRole) pt).getMaximumOccurs();
             return maximumOccurs > 1 ? Collections.EMPTY_LIST : null;       // No default value for associations.
         } else {
             throw unsupportedPropertyType(pt.getName());
@@ -281,7 +274,7 @@
     /**
      * Returns the default value to be returned by {@link #getPropertyValue(String)} for the given attribute type.
      */
-    private static <V> Object getDefaultValue(final AttributeType<V> attribute) {
+    private static <V> Object getDefaultValue(final DefaultAttributeType<V> attribute) {
         final V defaultValue = attribute.getDefaultValue();
         if (Field.isSingleton(attribute.getMaximumOccurs())) {
             return defaultValue;
@@ -311,12 +304,11 @@
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws PropertyNotFoundException if the given argument is not an attribute or association name of this feature.
+     * @throws IllegalArgumentException if the given argument is not an attribute or association name of this feature.
      *
      * @see AbstractAttribute#getValue()
      */
-    @Override
-    public abstract Object getPropertyValue(final String name) throws PropertyNotFoundException;
+    public abstract Object getPropertyValue(final String name) throws IllegalArgumentException;
 
     /**
      * Sets the value for the property of the given name.
@@ -329,20 +321,19 @@
      *
      * @param  name  The attribute name.
      * @param  value The new value for the given attribute (may be {@code null}).
-     * @throws PropertyNotFoundException if the given name is not an attribute or association name of this feature.
+     * @throws IllegalArgumentException if the given name is not an attribute or association name of this feature.
      * @throws ClassCastException if the value is not assignable to the expected value class.
-     * @throws InvalidPropertyValueException if the given value is not valid for a reason other than its type.
+     * @throws IllegalArgumentException if the given value is not valid for a reason other than its type.
      *
      * @see AbstractAttribute#setValue(Object)
      */
-    @Override
     public abstract void setPropertyValue(final String name, final Object value) throws IllegalArgumentException;
 
     /**
      * Returns the value of the given attribute, as a singleton or as a collection depending
      * on the maximum number of occurrences.
      */
-    static Object getAttributeValue(final Attribute<?> property) {
+    static Object getAttributeValue(final AbstractAttribute<?> property) {
         return Field.isSingleton(property.getType().getMaximumOccurs()) ? property.getValue() : property.getValues();
     }
 
@@ -350,7 +341,7 @@
      * Returns the value of the given association, as a singleton or as a collection depending
      * on the maximum number of occurrences.
      */
-    static Object getAssociationValue(final FeatureAssociation property) {
+    static Object getAssociationValue(final AbstractAssociation property) {
         return Field.isSingleton(property.getRole().getMaximumOccurs()) ? property.getValue() : property.getValues();
     }
 
@@ -358,10 +349,10 @@
      * Sets the value of the given property, with some minimal checks.
      */
     static void setPropertyValue(final Property property, final Object value) {
-        if (property instanceof Attribute<?>) {
-            setAttributeValue((Attribute<?>) property, value);
-        } else if (property instanceof FeatureAssociation) {
-            setAssociationValue((FeatureAssociation) property, value);
+        if (property instanceof AbstractAttribute<?>) {
+            setAttributeValue((AbstractAttribute<?>) property, value);
+        } else if (property instanceof AbstractAssociation) {
+            setAssociationValue((AbstractAssociation) property, value);
         } else {
             throw unsupportedPropertyType(property.getName());
         }
@@ -373,9 +364,9 @@
      * use {@link Validator} instead.
      */
     @SuppressWarnings("unchecked")
-    private static <V> void setAttributeValue(final Attribute<V> attribute, final Object value) {
+    private static <V> void setAttributeValue(final AbstractAttribute<V> attribute, final Object value) {
         if (value != null) {
-            final AttributeType<V> pt = attribute.getType();
+            final DefaultAttributeType<V> pt = attribute.getType();
             final Class<?> base = pt.getValueClass();
             if (!base.isInstance(value)) {
                 Object element = value;
@@ -386,7 +377,7 @@
                      */
                     final Iterator<?> it = ((Collection<?>) value).iterator();
                     do if (!it.hasNext()) {
-                        ((Attribute) attribute).setValues((Collection) value);
+                        ((AbstractAttribute) attribute).setValues((Collection) value);
                         return;
                     } while ((element = it.next()) == null || base.isInstance(element));
                     // Found an illegal value. Exeption is thrown below.
@@ -394,7 +385,7 @@
                 throw illegalValueClass(attribute.getName(), element); // 'element' can not be null here.
             }
         }
-        ((Attribute) attribute).setValue(value);
+        ((AbstractAttribute) attribute).setValue(value);
     }
 
     /**
@@ -402,24 +393,24 @@
      * For a more exhaustive validation, use {@link Validator} instead.
      */
     @SuppressWarnings("unchecked")
-    private static void setAssociationValue(final FeatureAssociation association, final Object value) {
+    private static void setAssociationValue(final AbstractAssociation association, final Object value) {
         if (value != null) {
-            final FeatureAssociationRole role = association.getRole();
-            final FeatureType base = role.getValueType();
-            if (value instanceof Feature) {
-                final FeatureType actual = ((Feature) value).getType();
+            final DefaultAssociationRole role = association.getRole();
+            final DefaultFeatureType base = role.getValueType();
+            if (value instanceof AbstractFeature) {
+                final DefaultFeatureType actual = ((AbstractFeature) value).getType();
                 if (base != actual && !DefaultFeatureType.maybeAssignableFrom(base, actual)) {
                     throw illegalPropertyType(role.getName(), actual.getName());
                 }
             } else if (value instanceof Collection<?>) {
                 verifyAssociationValues(role, (Collection<?>) value);
-                association.setValues((Collection<? extends Feature>) value);
+                association.setValues((Collection<? extends AbstractFeature>) value);
                 return; // Skip the setter at the end of this method.
             } else {
                 throw illegalValueClass(association.getName(), value);
             }
         }
-        association.setValue((Feature) value);
+        association.setValue((AbstractFeature) value);
     }
 
     /**
@@ -437,7 +428,7 @@
             if (value == null) {
                 return true;
             }
-            if (previous.getClass() == value.getClass() && !(value instanceof Feature)) {
+            if (previous.getClass() == value.getClass() && !(value instanceof AbstractFeature)) {
                 return true;
             }
         }
@@ -451,19 +442,19 @@
      * @param property The property to verify.
      */
     final void verifyPropertyType(final String name, final Property property) {
-        final PropertyType pt, base = type.getProperty(name);
-        if (property instanceof Attribute<?>) {
-            pt = ((Attribute<?>) property).getType();
-        } else if (property instanceof FeatureAssociation) {
-            pt = ((FeatureAssociation) property).getRole();
+        final AbstractIdentifiedType pt, base = type.getProperty(name);
+        if (property instanceof AbstractAttribute<?>) {
+            pt = ((AbstractAttribute<?>) property).getType();
+        } else if (property instanceof AbstractAssociation) {
+            pt = ((AbstractAssociation) property).getRole();
         } else {
             throw illegalPropertyType(base.getName(), property.getClass());
         }
         if (pt != base) {
             if (base == null) {
-                throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
             } else {
-                throw new InvalidPropertyValueException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
             }
         }
     }
@@ -473,14 +464,14 @@
      * to store. The returned value is usually the same than the given one, except in the case of collections.
      */
     final Object verifyPropertyValue(final String name, final Object value) {
-        final PropertyType pt = type.getProperty(name);
-        if (pt instanceof AttributeType<?>) {
+        final AbstractIdentifiedType pt = type.getProperty(name);
+        if (pt instanceof DefaultAttributeType<?>) {
             if (value != null) {
-                return verifyAttributeValue((AttributeType<?>) pt, value);
+                return verifyAttributeValue((DefaultAttributeType<?>) pt, value);
             }
-        } else if (pt instanceof FeatureAssociationRole) {
+        } else if (pt instanceof DefaultAssociationRole) {
             if (value != null) {
-                return verifyAssociationValue((FeatureAssociationRole) pt, value);
+                return verifyAssociationValue((DefaultAssociationRole) pt, value);
             }
         } else {
             throw unsupportedPropertyType(pt.getName());
@@ -498,7 +489,7 @@
      *
      * @param value The value, which shall be non-null.
      */
-    private static <T> Object verifyAttributeValue(final AttributeType<T> type, final Object value) {
+    private static <T> Object verifyAttributeValue(final DefaultAttributeType<T> type, final Object value) {
         final Class<T> valueClass = type.getValueClass();
         final boolean isSingleton = Field.isSingleton(type.getMaximumOccurs());
         if (valueClass.isInstance(value)) {
@@ -520,23 +511,23 @@
      *
      * @param value The value, which shall be non-null.
      */
-    private static Object verifyAssociationValue(final FeatureAssociationRole role, final Object value) {
+    private static Object verifyAssociationValue(final DefaultAssociationRole role, final Object value) {
         final boolean isSingleton = Field.isSingleton(role.getMaximumOccurs());
-        if (value instanceof Feature) {
+        if (value instanceof AbstractFeature) {
             /*
              * If the user gave us a single value, first verify its validity.
              * Then wrap it in a list of 1 element if this property is multi-valued.
              */
-            final FeatureType valueType = ((Feature) value).getType();
-            final FeatureType base = role.getValueType();
+            final DefaultFeatureType valueType = ((AbstractFeature) value).getType();
+            final DefaultFeatureType base = role.getValueType();
             if (base == valueType || DefaultFeatureType.maybeAssignableFrom(base, valueType)) {
-                return isSingleton ? value : singletonList(Feature.class, role.getMinimumOccurs(), value);
+                return isSingleton ? value : singletonList(AbstractFeature.class, role.getMinimumOccurs(), value);
             } else {
                 throw illegalPropertyType(role.getName(), valueType.getName());
             }
         } else if (!isSingleton && value instanceof Collection<?>) {
             verifyAssociationValues(role, (Collection<?>) value);
-            return CheckedArrayList.castOrCopy((Collection<?>) value, Feature.class);
+            return CheckedArrayList.castOrCopy((Collection<?>) value, AbstractFeature.class);
         } else {
             throw illegalValueClass(role.getName(), value);
         }
@@ -545,15 +536,15 @@
     /**
      * Verifies if all values in the given collection are valid instances of feature for the given association role.
      */
-    private static void verifyAssociationValues(final FeatureAssociationRole role, final Collection<?> values) {
-        final FeatureType base = role.getValueType();
+    private static void verifyAssociationValues(final DefaultAssociationRole role, final Collection<?> values) {
+        final DefaultFeatureType base = role.getValueType();
         int index = 0;
         for (final Object value : values) {
             ArgumentChecks.ensureNonNullElement("values", index, value);
-            if (!(value instanceof Feature)) {
+            if (!(value instanceof AbstractFeature)) {
                 throw illegalValueClass(role.getName(), value);
             }
-            final FeatureType type = ((Feature) value).getType();
+            final DefaultFeatureType type = ((AbstractFeature) value).getType();
             if (base != type && !DefaultFeatureType.maybeAssignableFrom(base, type)) {
                 throw illegalPropertyType(role.getName(), type.getName());
             }
@@ -593,8 +584,8 @@
     /**
      * Returns the exception for a property value (usually a feature) of wrong type.
      */
-    private static InvalidPropertyValueException illegalPropertyType(final GenericName name, final Object value) {
-        return new InvalidPropertyValueException(Errors.format(Errors.Keys.IllegalPropertyValueClass_2, name, value));
+    private static IllegalArgumentException illegalPropertyType(final GenericName name, final Object value) {
+        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyValueClass_2, name, value));
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
index 985dc2c..ded0b53 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
@@ -30,18 +30,22 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.IdentifiedType;
 
 
 /**
  * Identification and description information inherited by property types and feature types.
  *
+ * <div class="warning"><b>Warning:</b>
+ * This class is expected to implement a GeoAPI {@code IdentifiedType} interface in a future version.
+ * When such interface will be available, most references to {@code AbstractIdentifiedType} in the API
+ * will be replaced by references to the {@code IdentifiedType} interface.</div>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
  * @version 0.6
  * @module
  */
-public class AbstractIdentifiedType implements IdentifiedType, Serializable {
+public class AbstractIdentifiedType implements Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -211,7 +215,6 @@
      *
      * @return The type name.
      */
-    @Override
     public final GenericName getName() {
         return name;
     }
@@ -221,7 +224,6 @@
      *
      * @return Concise definition of the element.
      */
-    @Override
     public InternationalString getDefinition() {
         return definition;
     }
@@ -232,7 +234,6 @@
      *
      * @return Natural language designator for the element, or {@code null} if none.
      */
-    @Override
     public InternationalString getDesignation() {
         return designation;
     }
@@ -243,7 +244,6 @@
      *
      * @return Information beyond that required for concise definition of the element, or {@code null} if none.
      */
-    @Override
     public InternationalString getDescription() {
         return description;
     }
@@ -298,7 +298,9 @@
      * @param index     Index of the characteristics having the given name.
      * @throws IllegalArgumentException if the given name is null or have an empty string representation.
      */
-    static String toString(final GenericName name, final IdentifiedType container, final String argument, final int index) {
+    static String toString(final GenericName name, final AbstractIdentifiedType container,
+            final String argument, final int index)
+    {
         short key = Errors.Keys.MissingValueForProperty_1;
         if (name != null) {
             final String s = name.toString();
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
index e447045..89a1b6b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
@@ -30,13 +30,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
 
 
 /**
@@ -64,7 +57,7 @@
  *
  * @see DefaultFeatureType
  */
-public abstract class AbstractOperation extends AbstractIdentifiedType implements Operation {
+public abstract class AbstractOperation extends AbstractIdentifiedType {
     /**
      * For cross-version compatibility.
      */
@@ -116,16 +109,17 @@
      *
      * @return Description of the input parameters.
      */
-    @Override
     public abstract ParameterDescriptorGroup getParameters();
 
     /**
      * Returns the expected result type, or {@code null} if none.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.IdentifiedType}. This change is pending GeoAPI revision.</div>
+     *
      * @return The type of the result, or {@code null} if none.
      */
-    @Override
-    public abstract IdentifiedType getResult();
+    public abstract AbstractIdentifiedType getResult();
 
     /**
      * Executes the operation on the specified feature with the specified parameters.
@@ -148,14 +142,17 @@
      * in the Java language, and may be {@code null} if the operation does not need a feature instance
      * (like static methods in the Java language).</div>
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the parameter type and return value may
+     * be changed to {@code org.opengis.feature.Feature} and {@code org.opengis.feature.Property} respectively.
+     * This change is pending GeoAPI revision.</div>
+     *
      * @param  feature    The feature on which to execute the operation.
      *                    Can be {@code null} if the operation does not need feature instance.
      * @param  parameters The parameters to use for executing the operation.
      *                    Can be {@code null} if the operation does not take any parameters.
      * @return The operation result, or {@code null} if this operation does not produce any result.
      */
-    @Override
-    public abstract Property apply(Feature feature, ParameterValueGroup parameters);
+    public abstract Object apply(AbstractFeature feature, ParameterValueGroup parameters);
 
     /**
      * Returns the names of feature properties that this operation needs for performing its task.
@@ -235,11 +232,11 @@
         if (separator == ", ") {                    // Identity comparaison is okay here.
             buffer.append(')');
         }
-        final IdentifiedType result = getResult();
+        final AbstractIdentifiedType result = getResult();
         if (result != null) {
             final Object type;
-            if (result instanceof AttributeType<?>) {
-                type = Classes.getShortName(((AttributeType<?>) result).getValueClass());
+            if (result instanceof DefaultAttributeType<?>) {
+                type = Classes.getShortName(((DefaultAttributeType<?>) result).getValueClass());
             } else {
                 type = result.getName();
             }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java b/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
index 835e716..b5dd86b 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
@@ -24,12 +24,6 @@
 import org.apache.sis.internal.util.AbstractMap;
 import org.apache.sis.internal.util.AbstractMapEntry;
 
-// Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.PropertyNotFoundException;
-
 
 /**
  * Implementation of {@link AbstractAttribute#characteristics()} map.
@@ -40,16 +34,16 @@
  * @version 0.6
  * @module
  */
-final class CharacteristicMap extends AbstractMap<String,Attribute<?>> implements Cloneable {
+final class CharacteristicMap extends AbstractMap<String,AbstractAttribute<?>> implements Cloneable {
     /**
      * The attribute source for which to provide characteristics.
      */
-    private final Attribute<?> source;
+    private final AbstractAttribute<?> source;
 
     /**
      * Characteristics of the {@code source} attribute, created when first needed.
      */
-    Attribute<?>[] characterizedBy;
+    AbstractAttribute<?>[] characterizedBy;
 
     /**
      * Description of the attribute characteristics.
@@ -62,7 +56,7 @@
      * @param source The attribute which is characterized by {@code characterizedBy}.
      * @param characterizedBy Description of the characteristics of {@code source}.
      */
-    CharacteristicMap(final Attribute<?> source, final CharacteristicTypeMap types) {
+    CharacteristicMap(final AbstractAttribute<?> source, final CharacteristicTypeMap types) {
         this.source = source;
         this.types  = types;
     }
@@ -75,14 +69,14 @@
     @Override
     public CharacteristicMap clone() throws CloneNotSupportedException {
         final CharacteristicMap clone = (CharacteristicMap) super.clone();
-        Attribute<?>[] c = clone.characterizedBy;
+        AbstractAttribute<?>[] c = clone.characterizedBy;
         if (c != null) {
             clone.characterizedBy = c = c.clone();
             final Cloner cloner = new Cloner();
             for (int i=0; i<c.length; i++) {
-                final Attribute<?> attribute = c[i];
+                final AbstractAttribute<?> attribute = c[i];
                 if (attribute instanceof Cloneable) {
-                    c[i] = (Attribute<?>) cloner.clone(attribute);
+                    c[i] = (AbstractAttribute<?>) cloner.clone(attribute);
                 }
             }
         }
@@ -108,7 +102,7 @@
     @Override
     public boolean isEmpty() {
         if (characterizedBy != null) {
-            for (final Attribute<?> attribute : characterizedBy) {
+            for (final AbstractAttribute<?> attribute : characterizedBy) {
                 if (attribute != null) {
                     return false;
                 }
@@ -124,7 +118,7 @@
     public int size() {
         int n = 0;
         if (characterizedBy != null) {
-            for (final Attribute<?> attribute : characterizedBy) {
+            for (final AbstractAttribute<?> attribute : characterizedBy) {
                 if (attribute != null) {
                     n++;
                 }
@@ -137,7 +131,7 @@
      * Returns the attribute characteristic for the given name, or {@code null} if none.
      */
     @Override
-    public Attribute<?> get(final Object key) {
+    public AbstractAttribute<?> get(final Object key) {
         if (characterizedBy != null) {
             final Integer index = types.indices.get(key);
             if (index != null) {
@@ -151,11 +145,11 @@
      * Removes the attribute characteristic for the given name.
      */
     @Override
-    public Attribute<?> remove(final Object key) {
+    public AbstractAttribute<?> remove(final Object key) {
         if (characterizedBy != null) {
             final Integer index = types.indices.get(key);
             if (index != null) {
-                final Attribute<?> previous = characterizedBy[index];
+                final AbstractAttribute<?> previous = characterizedBy[index];
                 characterizedBy[index] = null;
                 return previous;
             }
@@ -168,13 +162,13 @@
      *
      * @param  key The name for which to get the characteristic index.
      * @return The index for the characteristic of the given name.
-     * @throws PropertyNotFoundException if the given key is not the name of a characteristic in this map.
+     * @throws IllegalArgumentException if the given key is not the name of a characteristic in this map.
      */
     private int indexOf(final String key) {
         ArgumentChecks.ensureNonNull("key", key);
         final Integer index = types.indices.get(key);
         if (index == null) {
-            throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, source.getName(), key));
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, source.getName(), key));
         }
         return index;
     }
@@ -187,12 +181,12 @@
      * @param index Index of the expected attribute type.
      * @param type  The actual attribute type.
      */
-    final void verifyAttributeType(final int index, final AttributeType<?> type) {
-        final AttributeType<?> expected = types.characterizedBy[index];
+    final void verifyAttributeType(final int index, final DefaultAttributeType<?> type) {
+        final DefaultAttributeType<?> expected = types.characterizedBy[index];
         if (!expected.equals(type)) {
             final GenericName en = expected.getName();
             final GenericName an = type.getName();
-            throw new InvalidPropertyValueException(String.valueOf(en).equals(String.valueOf(an))
+            throw new IllegalArgumentException(String.valueOf(en).equals(String.valueOf(an))
                     ? Errors.format(Errors.Keys.MismatchedPropertyType_1, en)
                     : Errors.format(Errors.Keys.CanNotAssign_2, en.push(source.getName()), an));
         }
@@ -205,14 +199,14 @@
      * @throws IllegalArgumentException if the given key is not the name of a characteristic in this map.
      */
     @Override
-    public Attribute<?> put(final String key, final Attribute<?> value) {
+    public AbstractAttribute<?> put(final String key, final AbstractAttribute<?> value) {
         final int index = indexOf(key);
         ArgumentChecks.ensureNonNull("value", value);
         verifyAttributeType(index, value.getType());
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
-        final Attribute<?> previous = characterizedBy[index];
+        final AbstractAttribute<?> previous = characterizedBy[index];
         characterizedBy[index] = value;
         return previous;
     }
@@ -229,7 +223,7 @@
     protected boolean addKey(final String name) {
         final int index = indexOf(name);
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
         if (characterizedBy[index] == null) {
             characterizedBy[index] = types.characterizedBy[index].newInstance();
@@ -247,14 +241,14 @@
      * @throws IllegalStateException if another characteristic already exists for the characteristic name.
      */
     @Override
-    protected boolean addValue(final Attribute<?> value) {
+    protected boolean addValue(final AbstractAttribute<?> value) {
         ArgumentChecks.ensureNonNull("value", value);
         final int index = indexOf(value.getName().toString());
         verifyAttributeType(index, value.getType());
         if (characterizedBy == null) {
-            characterizedBy = new Attribute<?>[types.characterizedBy.length];
+            characterizedBy = new AbstractAttribute<?>[types.characterizedBy.length];
         }
-        final Attribute<?> previous = characterizedBy[index];
+        final AbstractAttribute<?> previous = characterizedBy[index];
         if (previous == null) {
             characterizedBy[index] = value;
             return true;
@@ -270,16 +264,16 @@
      * Returns an iterator over the entries.
      */
     @Override
-    protected EntryIterator<String, Attribute<?>> entryIterator() {
+    protected EntryIterator<String, AbstractAttribute<?>> entryIterator() {
         if (characterizedBy == null) {
             return null;
         }
-        return new EntryIterator<String, Attribute<?>>() {
+        return new EntryIterator<String, AbstractAttribute<?>>() {
             /** Index of the current element to return in the iteration. */
             private int index = -1;
 
             /** The element to return, or {@code null} if we reached the end of iteration. */
-            private Attribute<?> value;
+            private AbstractAttribute<?> value;
 
             /** Returns {@code true} if there is more entries in the iteration. */
             @Override protected boolean next() {
@@ -297,12 +291,12 @@
             }
 
             /** Returns the attribute characteristic (never {@code null}). */
-            @Override protected Attribute<?> getValue() {
+            @Override protected AbstractAttribute<?> getValue() {
                 return value;
             }
 
             /** Creates and return the next entry. */
-            @Override protected Map.Entry<String, Attribute<?>> getEntry() {
+            @Override protected Map.Entry<String, AbstractAttribute<?>> getEntry() {
                 return new Entry(index, value);
             }
 
@@ -318,15 +312,15 @@
      * The key and value are never null, even in case of concurrent modification.
      * This entry supports the {@link #setValue(Attribute)} operation.
      */
-    private final class Entry extends AbstractMapEntry<String, Attribute<?>> {
+    private final class Entry extends AbstractMapEntry<String, AbstractAttribute<?>> {
         /** Index of the attribute characteristics represented by this entry. */
         private final int index;
 
         /** The current attribute value, which is guaranteed to be non-null. */
-        private Attribute<?> value;
+        private AbstractAttribute<?> value;
 
         /** Creates a new entry for the characteristic at the given index. */
-        Entry(final int index, final Attribute<?> value) {
+        Entry(final int index, final AbstractAttribute<?> value) {
             this.index = index;
             this.value = value;
         }
@@ -337,15 +331,15 @@
         }
 
         /** Returns the attribute characteristic (never {@code null}). */
-        @Override public Attribute<?> getValue() {
+        @Override public AbstractAttribute<?> getValue() {
             return value;
         }
 
         /** Sets the attribute characteristic. */
-        @Override public Attribute<?> setValue(final Attribute<?> value) {
+        @Override public AbstractAttribute<?> setValue(final AbstractAttribute<?> value) {
             ArgumentChecks.ensureNonNull("value", value);
             verifyAttributeType(index, value.getType());
-            final Attribute<?> previous = this.value;
+            final AbstractAttribute<?> previous = this.value;
             characterizedBy[index] = value;
             this.value = value;
             return previous;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java b/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
index 8fdf502..71b69d1 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicTypeMap.java
@@ -26,9 +26,6 @@
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNullElement;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-
 
 /**
  * Implementation of the map returned by {@link DefaultAttributeType#characteristics()}.
@@ -38,7 +35,7 @@
  * The straightforward approach would be to store the attributes directly as values in a standard {@code HashMap}.
  * But instead of that, we store attributes in an array and the array indices in a {@code HashMap}. This level of
  * indirection is useless if we consider only the {@link DefaultAttributeType#characteristics()} method, since a
- * standard {@code HashMap<String,AttributeType>} would work as well or better. However this level of indirection
+ * standard {@code HashMap<String,DefaultAttributeType>} would work as well or better. However this level of indirection
  * become useful for {@link CharacteristicMap} (the map returned by {@link DefaultAttribute#characteristics()}),
  * since it allows a more efficient storage. We do this effort because some applications may create a very large
  * amount of attribute instances.
@@ -48,17 +45,17 @@
  * @version 0.5
  * @module
  */
-final class CharacteristicTypeMap extends AbstractMap<String,AttributeType<?>> {
+final class CharacteristicTypeMap extends AbstractMap<String,DefaultAttributeType<?>> {
     /**
      * For sharing the same {@code CharacteristicTypeMap} instances among the attribute types
      * having the same characteristics.
      */
     @SuppressWarnings("unchecked")
-    private static final WeakValueHashMap<AttributeType<?>[],CharacteristicTypeMap> SHARED =
-            new WeakValueHashMap<AttributeType<?>[],CharacteristicTypeMap>((Class) AttributeType[].class);
+    private static final WeakValueHashMap<DefaultAttributeType<?>[],CharacteristicTypeMap> SHARED =
+            new WeakValueHashMap<DefaultAttributeType<?>[],CharacteristicTypeMap>((Class) DefaultAttributeType[].class);
 
     /*
-     * This class has intentionally no reference to the AttributeType for which we are providing characteristics.
+     * This class has intentionally no reference to the DefaultAttributeType for which we are providing characteristics.
      * This allows us to use the same CharacteristicTypeMap instance for various attribute types having the same
      * characteristic (e.g. many measurements may have an "accuracy" characteristic).
      */
@@ -67,7 +64,7 @@
      * Characteristics of an other attribute type (the {@code source} attribute given to the constructor).
      * This array shall not be modified.
      */
-    final AttributeType<?>[] characterizedBy;
+    final DefaultAttributeType<?>[] characterizedBy;
 
     /**
      * The names of attribute types listed in the {@link #characterizedBy} array,
@@ -86,7 +83,7 @@
      * @return A map for this given characteristics.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
-    static CharacteristicTypeMap create(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
+    static CharacteristicTypeMap create(final DefaultAttributeType<?> source, final DefaultAttributeType<?>[] characterizedBy) {
         CharacteristicTypeMap map;
         synchronized (SHARED) {
             map = SHARED.get(characterizedBy);
@@ -108,12 +105,12 @@
      * @param  characterizedBy Characteristics of {@code source}. Should not be empty.
      * @throws IllegalArgumentException if two characteristics have the same name.
      */
-    private CharacteristicTypeMap(final AttributeType<?> source, final AttributeType<?>[] characterizedBy) {
+    private CharacteristicTypeMap(final DefaultAttributeType<?> source, final DefaultAttributeType<?>[] characterizedBy) {
         this.characterizedBy = characterizedBy;
         int index = 0;
         final Map<String,Integer> indices = new HashMap<String,Integer>(Containers.hashMapCapacity(characterizedBy.length));
         for (int i=0; i<characterizedBy.length; i++) {
-            final AttributeType<?> attribute = characterizedBy[i];
+            final DefaultAttributeType<?> attribute = characterizedBy[i];
             ensureNonNullElement("characterizedBy", i, attribute);
             final String name = AbstractIdentifiedType.toString(attribute.getName(), source, "characterizedBy", i);
             if (indices.put(name, index++) != null) {
@@ -152,7 +149,7 @@
      */
     @Override
     public boolean containsValue(final Object key) {
-        for (final AttributeType<?> type : characterizedBy) {
+        for (final DefaultAttributeType<?> type : characterizedBy) {
             if (type.equals(key)) {
                 return true;
             }
@@ -164,7 +161,7 @@
      * Returns the attribute characteristic for the given name, or {@code null} if none.
      */
     @Override
-    public AttributeType<?> get(final Object key) {
+    public DefaultAttributeType<?> get(final Object key) {
         final Integer index = indices.get(key);
         return (index != null) ? characterizedBy[index] : null;
     }
@@ -174,13 +171,13 @@
      * This is not the iterator returned by public API like {@code Map.entrySet().iterator()}.
      */
     @Override
-    protected EntryIterator<String, AttributeType<?>> entryIterator() {
-        return new EntryIterator<String, AttributeType<?>>() {
+    protected EntryIterator<String, DefaultAttributeType<?>> entryIterator() {
+        return new EntryIterator<String, DefaultAttributeType<?>>() {
             /** Index of the next element to return in the iteration. */
             private int index;
 
             /** Value of current entry. */
-            private AttributeType<?> value;
+            private DefaultAttributeType<?> value;
 
             /**
              * Returns {@code true} if there is more entries in the iteration.
@@ -206,7 +203,7 @@
              * Returns the attribute characteristic contained in this entry.
              */
             @Override
-            protected AttributeType<?> getValue() {
+            protected DefaultAttributeType<?> getValue() {
                 return value;
             }
         };
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
index ec23dad..8857973 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
@@ -27,13 +27,6 @@
 
 import static org.apache.sis.util.ArgumentChecks.*;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.FeatureAssociationRole;
-
 
 /**
  * Indicates the role played by the association between two features.
@@ -60,7 +53,7 @@
  * @see DefaultFeatureType
  * @see AbstractAssociation
  */
-public class DefaultAssociationRole extends FieldType implements FeatureAssociationRole {
+public class DefaultAssociationRole extends FieldType {
     /**
      * For cross-version compatibility.
      */
@@ -124,7 +117,7 @@
      *
      * @see org.apache.sis.feature.builder.AssociationRoleBuilder
      */
-    public DefaultAssociationRole(final Map<String,?> identification, final FeatureType valueType,
+    public DefaultAssociationRole(final Map<String,?> identification, final DefaultFeatureType valueType,
             final int minimumOccurs, final int maximumOccurs)
     {
         super(identification, minimumOccurs, maximumOccurs);
@@ -199,7 +192,7 @@
                  * this desired feature in an association of the 'creating' feature, instead than beeing
                  * the 'creating' feature itself. This is a little bit unusual, but not illegal.
                  */
-                final List<FeatureType> deferred = new ArrayList<FeatureType>();
+                final List<DefaultFeatureType> deferred = new ArrayList<DefaultFeatureType>();
                 type = search(creating, name, deferred);
                 if (type == null) {
                     /*
@@ -231,27 +224,25 @@
      * @return The feature of the given name, or {@code null} if none.
      */
     @SuppressWarnings("null")
-    private static FeatureType search(final FeatureType feature, final GenericName name, final List<FeatureType> deferred) {
+    private static DefaultFeatureType search(final DefaultFeatureType feature, final GenericName name,
+            final List<DefaultFeatureType> deferred)
+    {
         /*
          * Search only in associations declared in the given feature, not in inherited associations.
          * The inherited associations will be checked in a separated loop below if we did not found
          * the request feature type in explicitly declared associations.
          */
-        for (final PropertyType property : feature.getProperties(false)) {
-            if (property instanceof FeatureAssociationRole) {
+        for (final AbstractIdentifiedType property : feature.getProperties(false)) {
+            if (property instanceof DefaultAssociationRole) {
                 final FeatureType valueType;
-                if (property instanceof DefaultAssociationRole) {
-                    valueType = ((DefaultAssociationRole) property).valueType;
-                    if (valueType instanceof NamedFeatureType) {
-                        continue; // Skip unresolved feature types.
-                    }
-                } else {
-                    valueType = ((FeatureAssociationRole) property).getValueType();
+                valueType = ((DefaultAssociationRole) property).valueType;
+                if (valueType instanceof NamedFeatureType) {
+                    continue; // Skip unresolved feature types.
                 }
                 if (name.equals(valueType.getName())) {
-                    return valueType;
+                    return (DefaultFeatureType) valueType;
                 }
-                deferred.add(valueType);
+                deferred.add((DefaultFeatureType) valueType);
             }
         }
         /*
@@ -260,7 +251,7 @@
          * but not necessarily the same feature type (may be a subtype). This is equivalent to
          * "covariant return type" in the Java language.
          */
-        for (FeatureType type : feature.getSuperTypes()) {
+        for (DefaultFeatureType type : feature.getSuperTypes()) {
             if (name.equals(type.getName())) {
                 return type;
             }
@@ -286,10 +277,10 @@
      * @param  done The feature types collected by {@link #search(FeatureType, GenericName, List)}.
      * @return The feature of the given name, or {@code null} if none.
      */
-    private static FeatureType deepSearch(final List<FeatureType> deferred, final GenericName name) {
+    private static DefaultFeatureType deepSearch(final List<DefaultFeatureType> deferred, final GenericName name) {
         final Map<FeatureType,Boolean> done = new IdentityHashMap<FeatureType,Boolean>(8);
         for (int i=0; i<deferred.size();) {
-            FeatureType valueType = deferred.get(i++);
+            DefaultFeatureType valueType = deferred.get(i++);
             if (done.put(valueType, Boolean.TRUE) == null) {
                 deferred.subList(0, i).clear(); // Discard previous value for making more room.
                 valueType = search(valueType, name, deferred);
@@ -305,13 +296,15 @@
     /**
      * Returns the type of feature values.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.FeatureType}. This change is pending GeoAPI revision.</div>
+     *
      * @return The type of feature values.
      * @throws IllegalStateException if the feature type has been specified
      *         {@linkplain #DefaultAssociationRole(Map, GenericName, int, int) only by its name}
      *         and not yet resolved.
      */
-    @Override
-    public final FeatureType getValueType() {
+    public final DefaultFeatureType getValueType() {
         /*
          * This method shall be final for consistency with other methods in this classes
          * which use the 'valueType' field directly. Furthermore, this method is invoked
@@ -321,42 +314,44 @@
         if (type instanceof NamedFeatureType) {
             throw new IllegalStateException(Errors.format(Errors.Keys.UnresolvedFeatureName_1, getName()));
         }
-        return type;
+        return (DefaultFeatureType) type;
     }
 
     /**
      * Returns the name of the feature type. This information is always available
      * even when the name has not yet been {@linkplain #resolve resolved}.
      */
-    static GenericName getValueTypeName(final FeatureAssociationRole role) {
-        return (role instanceof DefaultAssociationRole ? ((DefaultAssociationRole) role).valueType : role.getValueType()).getName();
+    static GenericName getValueTypeName(final DefaultAssociationRole role) {
+        // Method is static for compatibility with branches on GeoAPI snapshots.
+        return role.valueType.getName();
     }
 
     /**
      * Returns the name of the property to use as a title for the associated feature, or {@code null} if none.
      * This method searches for the first attribute having a value class assignable to {@link CharSequence}.
+     *
+     * <p><b>API note:</b> a non-static method would be more elegant in this "SIS for GeoAPI 3.0" branch.
+     * However this method needs to be static in other SIS branches, because they work with interfaces
+     * rather than SIS implementation. We keep the method static in this branch too for easier merges.</p>
      */
-    static String getTitleProperty(final FeatureAssociationRole role) {
-        if (role instanceof DefaultAssociationRole) {
-            String p = ((DefaultAssociationRole) role).titleProperty; // No synchronization - not a big deal if computed twice.
-            if (p != null) {
-                return p.isEmpty() ? null : p;
-            }
-            p = searchTitleProperty(role);
-            ((DefaultAssociationRole) role).titleProperty = (p != null) ? p : "";
-            return p;
+    static String getTitleProperty(final DefaultAssociationRole role) {
+        String p = role.titleProperty; // No synchronization - not a big deal if computed twice.
+        if (p != null) {
+            return p.isEmpty() ? null : p;
         }
-        return searchTitleProperty(role);
+        p = searchTitleProperty(role);
+        role.titleProperty = (p != null) ? p : "";
+        return p;
     }
 
     /**
      * Implementation of {@link #getTitleProperty(FeatureAssociationRole)} for first search,
      * or for non-SIS {@code FeatureAssociationRole} implementations.
      */
-    private static String searchTitleProperty(final FeatureAssociationRole role) {
-        for (final PropertyType type : role.getValueType().getProperties(true)) {
-            if (type instanceof AttributeType<?>) {
-                final AttributeType<?> pt = (AttributeType<?>) type;
+    private static String searchTitleProperty(final DefaultAssociationRole role) {
+        for (final AbstractIdentifiedType type : role.getValueType().getProperties(true)) {
+            if (type instanceof DefaultAttributeType<?>) {
+                final DefaultAttributeType<?> pt = (DefaultAttributeType<?>) type;
                 if (pt.getMaximumOccurs() != 0 && CharSequence.class.isAssignableFrom(pt.getValueClass())) {
                     return pt.getName().toString();
                 }
@@ -396,8 +391,7 @@
      *
      * @see AbstractAssociation#create(FeatureAssociationRole)
      */
-    @Override
-    public FeatureAssociation newInstance() {
+    public AbstractAssociation newInstance() {
         return AbstractAssociation.create(this);
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
index 008c86e..0a408bb 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
@@ -32,8 +32,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
 
 
 /**
@@ -48,6 +46,11 @@
  * Attribute characterization (discussed below) is similar to {@link java.lang.annotation.Annotation}.
  * </div>
  *
+ * <div class="warning"><b>Warning:</b>
+ * This class is expected to implement a GeoAPI {@code AttributeType} interface in a future version.
+ * When such interface will be available, most references to {@code DefaultAttributeType} in current
+ * API will be replaced by references to the {@code AttributeType} interface.</div>
+ *
  * <div class="section">Value type</div>
  * Attributes can be used for both spatial and non-spatial properties.
  * Some examples are:
@@ -105,7 +108,7 @@
  * @see DefaultFeatureType
  * @see AbstractAttribute
  */
-public class DefaultAttributeType<V> extends FieldType implements AttributeType<V> {
+public class DefaultAttributeType<V> extends FieldType {
     /**
      * For cross-version compatibility.
      */
@@ -182,7 +185,7 @@
      */
     public DefaultAttributeType(final Map<String,?> identification, final Class<V> valueClass,
             final int minimumOccurs, final int maximumOccurs, final V defaultValue,
-            final AttributeType<?>... characterizedBy)
+            final DefaultAttributeType<?>... characterizedBy)
     {
         super(identification, minimumOccurs, maximumOccurs);
         ensureNonNull("valueClass",   valueClass);
@@ -215,7 +218,7 @@
     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
         in.defaultReadObject();
         try {
-            final AttributeType<?>[] characterizedBy = (AttributeType<?>[]) in.readObject();
+            final DefaultAttributeType<?>[] characterizedBy = (DefaultAttributeType<?>[]) in.readObject();
             if (characterizedBy != null) {
                 characteristics = CharacteristicTypeMap.create(this, characterizedBy);
             }
@@ -229,7 +232,6 @@
      *
      * @return The type of attribute values.
      */
-    @Override
     public final Class<V> getValueClass() {
         return valueClass;
     }
@@ -281,7 +283,6 @@
      *
      * @return The default value for the attribute, or {@code null} if none.
      */
-    @Override
     public V getDefaultValue() {
         return defaultValue;
     }
@@ -305,9 +306,8 @@
      *
      * @see AbstractAttribute#characteristics()
      */
-    @Override
-    public Map<String,AttributeType<?>> characteristics() {
-        return (characteristics != null) ? characteristics : Collections.<String,AttributeType<?>>emptyMap();
+    public Map<String,DefaultAttributeType<?>> characteristics() {
+        return (characteristics != null) ? characteristics : Collections.<String,DefaultAttributeType<?>>emptyMap();
     }
 
     /**
@@ -315,10 +315,9 @@
      *
      * @return A new attribute instance.
      *
-     * @see AbstractAttribute#create(AttributeType)
+     * @see AbstractAttribute#create(DefaultAttributeType)
      */
-    @Override
-    public Attribute<V> newInstance() {
+    public AbstractAttribute<V> newInstance() {
         return AbstractAttribute.create(this);
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
index 6d79e90..996c16f 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
@@ -39,16 +39,7 @@
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 // Branch-dependent imports
-import org.apache.sis.internal.jdk7.Objects;
 import org.apache.sis.internal.jdk8.JDK8;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.Operation;
-import org.opengis.feature.FeatureInstantiationException;
-import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -59,6 +50,11 @@
  * compared to the Java language, {@code FeatureType} is equivalent to {@link Class} while
  * {@code Feature} instances are equivalent to {@link Object} instances of that class.</div>
  *
+ * <div class="warning"><b>Warning:</b>
+ * This class is expected to implement a GeoAPI {@code FeatureType} interface in a future version.
+ * When such interface will be available, most references to {@code DefaultFeatureType} in the API
+ * will be replaced by references to the {@code FeatureType} interface.</div>
+ *
  * <div class="section">Naming</div>
  * The feature type {@linkplain #getName() name} is mandatory and should be unique. Those names are the main
  * criterion used for deciding if a feature type {@linkplain #isAssignableFrom is assignable from} another type.
@@ -153,13 +149,13 @@
      *
      * @see #getSuperTypes()
      */
-    private final Set<FeatureType> superTypes;
+    private final Set<DefaultFeatureType> superTypes;
 
     /**
-     * The names of all parents of this feature type, including parents of parents.
-     * This is used for a more efficient implementation of {@link #isAssignableFrom(FeatureType)}.
+     * The names of all parents of this feature type, including parents of parents. This is used
+     * for a more efficient implementation of {@link #isAssignableFrom(DefaultFeatureType)}.
      *
-     * @see #isAssignableFrom(FeatureType)
+     * @see #isAssignableFrom(DefaultFeatureType)
      */
     private transient Set<GenericName> assignableTo;
 
@@ -169,7 +165,7 @@
      *
      * @see #getProperties(boolean)
      */
-    private final List<PropertyType> properties;
+    private final List<AbstractIdentifiedType> properties;
 
     /**
      * All properties, including the ones declared in the super-types.
@@ -177,7 +173,7 @@
      *
      * @see #getProperties(boolean)
      */
-    private transient Collection<PropertyType> allProperties;
+    private transient Collection<AbstractIdentifiedType> allProperties;
 
     /**
      * A lookup table for fetching properties by name, including the properties from super-types.
@@ -185,7 +181,7 @@
      *
      * @see #getProperty(String)
      */
-    private transient Map<String, PropertyType> byName;
+    private transient Map<String, AbstractIdentifiedType> byName;
 
     /**
      * Indices of properties in an array of properties similar to {@link #properties},
@@ -237,6 +233,12 @@
      *   </tr>
      * </table>
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the type of array elements may be
+     * changed to {@code org.opengis.feature.FeatureType} and {@code org.opengis.feature.PropertyType}.
+     * This change is pending GeoAPI revision. In the meantime, make sure that the {@code properties}
+     * array contains only attribute types, association roles or operations, <strong>not</strong> other
+     * feature types since the later are not properties in the ISO sense.</div>
+     *
      * @param identification The name and other information to be given to this feature type.
      * @param isAbstract     If {@code true}, the feature type acts as an abstract super-type.
      * @param superTypes     The parents of this feature type, or {@code null} or empty if none.
@@ -247,7 +249,7 @@
      */
     @SuppressWarnings("ThisEscapedInObjectConstruction")
     public DefaultFeatureType(final Map<String,?> identification, final boolean isAbstract,
-            final FeatureType[] superTypes, final PropertyType... properties)
+            final DefaultFeatureType[] superTypes, final AbstractIdentifiedType... properties)
     {
         super(identification);
         ArgumentChecks.ensureNonNull("properties", properties);
@@ -266,7 +268,7 @@
         switch (properties.length) {
             case 0:  this.properties = Collections.emptyList(); break;
             case 1:  this.properties = Collections.singletonList(properties[0]); break;
-            default: this.properties = UnmodifiableArrayList.wrap(Arrays.copyOf(properties, properties.length, PropertyType[].class)); break;
+            default: this.properties = UnmodifiableArrayList.wrap(Arrays.copyOf(properties, properties.length, AbstractIdentifiedType[].class)); break;
         }
         computeTransientFields();
         isResolved = resolve(this, null, isSimple);
@@ -303,12 +305,12 @@
      */
     private void computeTransientFields() {
         final int capacity = Containers.hashMapCapacity(properties.size());
-        byName       = new LinkedHashMap<String,PropertyType>(capacity);
+        byName       = new LinkedHashMap<String,AbstractIdentifiedType>(capacity);
         indices      = new LinkedHashMap<String,Integer>(capacity);
         assignableTo = new HashSet<GenericName>(4);
         assignableTo.add(super.getName());
         scanPropertiesFrom(this);
-        allProperties = UnmodifiableArrayList.wrap(byName.values().toArray(new PropertyType[byName.size()]));
+        allProperties = UnmodifiableArrayList.wrap(byName.values().toArray(new AbstractIdentifiedType[byName.size()]));
         /*
          * Now check if the feature is simple/complex or dense/sparse. We perform this check after we finished
          * to create the list of all properties, because some properties may be overridden and we want to take
@@ -317,16 +319,16 @@
         isSimple = true;
         int index = 0;
         int mandatory = 0; // Count of mandatory properties.
-        for (final Map.Entry<String,PropertyType> entry : byName.entrySet()) {
+        for (final Map.Entry<String,AbstractIdentifiedType> entry : byName.entrySet()) {
             final int minimumOccurs, maximumOccurs;
-            final PropertyType property = entry.getValue();
-            if (property instanceof AttributeType<?>) {
-                minimumOccurs = ((AttributeType<?>) property).getMinimumOccurs();
-                maximumOccurs = ((AttributeType<?>) property).getMaximumOccurs();
+            final AbstractIdentifiedType property = entry.getValue();
+            if (property instanceof DefaultAttributeType<?>) { // Other SIS branches check for AttributeType instead.
+                minimumOccurs = ((DefaultAttributeType<?>) property).getMinimumOccurs();
+                maximumOccurs = ((DefaultAttributeType<?>) property).getMaximumOccurs();
                 isSimple &= (minimumOccurs == maximumOccurs);
-            } else if (property instanceof FeatureAssociationRole) {
-                minimumOccurs = ((FeatureAssociationRole) property).getMinimumOccurs();
-                maximumOccurs = ((FeatureAssociationRole) property).getMaximumOccurs();
+            } else if (property instanceof FieldType) { // TODO: check for AssociationRole instead (after GeoAPI upgrade).
+                minimumOccurs = ((FieldType) property).getMinimumOccurs();
+                maximumOccurs = ((FieldType) property).getMaximumOccurs();
                 isSimple = false;
             } else {
                 if (isParameterlessOperation(property)) {
@@ -349,8 +351,8 @@
          *
          * In the 'aliases' map below, null values will be assigned to ambiguous short names.
          */
-        final Map<String, PropertyType> aliases = new LinkedHashMap<String, PropertyType>();
-        for (final PropertyType property : allProperties) {
+        final Map<String, AbstractIdentifiedType> aliases = new LinkedHashMap<String, AbstractIdentifiedType>();
+        for (final AbstractIdentifiedType property : allProperties) {
             final GenericName name = property.getName();
             final LocalName tip = name.tip();
             if (tip != name) {  // Slight optimization for a common case.
@@ -360,8 +362,8 @@
                 }
             }
         }
-        for (final Map.Entry<String,PropertyType> entry : aliases.entrySet()) {
-            final PropertyType property = entry.getValue();
+        for (final Map.Entry<String,AbstractIdentifiedType> entry : aliases.entrySet()) {
+            final AbstractIdentifiedType property = entry.getValue();
             if (property != null) {
                 final String tip = entry.getKey();
                 if (JDK8.putIfAbsent(byName, tip, property) == null) {
@@ -404,17 +406,17 @@
      * @param  source The feature from which to get properties.
      * @throws IllegalArgumentException if two properties have the same name.
      */
-    private void scanPropertiesFrom(final FeatureType source) {
-        for (final FeatureType parent : source.getSuperTypes()) {
+    private void scanPropertiesFrom(final DefaultFeatureType source) {
+        for (final DefaultFeatureType parent : source.getSuperTypes()) {
             if (assignableTo.add(parent.getName())) {
                 scanPropertiesFrom(parent);
             }
         }
         int index = -1;
-        for (final PropertyType property : source.getProperties(false)) {
+        for (final AbstractIdentifiedType property : source.getProperties(false)) {
             ArgumentChecks.ensureNonNullElement("properties", ++index, property);
             final String name = toString(property.getName(), source, "properties", index);
-            final PropertyType previous = byName.put(name, property);
+            final AbstractIdentifiedType previous = byName.put(name, property);
             if (previous != null) {
                 if (!isAssignableIgnoreName(previous, property)) {
                     final GenericName owner = ownerOf(this, previous);
@@ -429,12 +431,16 @@
      * Returns the name of the feature which defines the given property, or {@code null} if not found.
      * This method is for information purpose when producing an error message - its implementation does
      * not need to be efficient.
+     *
+     * <p><b>API note:</b> a non-static method would be more elegant in this "SIS for GeoAPI 3.0" branch.
+     * However this method needs to be static in other SIS branches, because they work with interfaces
+     * rather than SIS implementation. We keep the method static in this branch too for easier merges.</p>
      */
-    private static GenericName ownerOf(final FeatureType type, final PropertyType property) {
+    private static GenericName ownerOf(final DefaultFeatureType type, final AbstractIdentifiedType property) {
         if (type.getProperties(false).contains(property)) {
             return type.getName();
         }
-        for (final FeatureType superType : type.getSuperTypes()) {
+        for (final DefaultFeatureType superType : type.getSuperTypes()) {
             final GenericName owner = ownerOf(superType, property);
             if (owner != null) {
                 return owner;
@@ -458,19 +464,12 @@
      * @param  previous Previous results, for avoiding never ending loop.
      * @return {@code true} if all names have been resolved.
      */
-    private boolean resolve(final FeatureType feature, final Map<FeatureType,Boolean> previous) {
+    private boolean resolve(final DefaultFeatureType feature, final Map<FeatureType,Boolean> previous) {
         /*
          * The isResolved field is used only as a cache for skipping completely the DefaultFeatureType instance if
-         * we have determined that there is no unresolved name.  If the given argument is not a DefaultFeatureType
-         * instance, conservatively assumes 'isSimple'. It may cause more calculation than needed, but should not
-         * change the result.
+         * we have determined that there is no unresolved name.
          */
-        if (feature instanceof DefaultFeatureType) {
-            final DefaultFeatureType dt = (DefaultFeatureType) feature;
-            return dt.isResolved = resolve(feature, previous, dt.isResolved);
-        } else {
-            return resolve(feature, previous, feature.isSimple());
-        }
+        return feature.isResolved = resolve(feature, previous, feature.isResolved);
     }
 
     /**
@@ -481,19 +480,17 @@
      * @param  resolved {@code true} if we already know that all names are resolved.
      * @return {@code true} if all names have been resolved.
      */
-    private boolean resolve(final FeatureType feature, Map<FeatureType,Boolean> previous, boolean resolved) {
+    private boolean resolve(final DefaultFeatureType feature, Map<FeatureType,Boolean> previous, boolean resolved) {
         if (!resolved) {
             resolved = true;
-            for (final FeatureType type : feature.getSuperTypes()) {
+            for (final DefaultFeatureType type : feature.getSuperTypes()) {
                 resolved &= resolve(type, previous);
             }
-            for (final PropertyType property : feature.getProperties(false)) {
-                if (property instanceof FeatureAssociationRole) {
-                    if (property instanceof DefaultAssociationRole) {
-                        if (!((DefaultAssociationRole) property).resolve(this)) {
-                            resolved = false;
-                            continue;
-                        }
+            for (final AbstractIdentifiedType property : feature.getProperties(false)) {
+                if (property instanceof DefaultAssociationRole) {
+                    if (!((DefaultAssociationRole) property).resolve(this)) {
+                        resolved = false;
+                        continue;
                     }
                     /*
                      * Resolve recursively the associated features, with a check against infinite recursivity.
@@ -501,7 +498,7 @@
                      * may not be the most accurate answer, but will not cause any more hurt than checking more
                      * often than necessary.
                      */
-                    final FeatureType valueType = ((FeatureAssociationRole) property).getValueType();
+                    final DefaultFeatureType valueType = ((DefaultAssociationRole) property).getValueType();
                     if (valueType != this) {
                         if (previous == null) {
                             previous = new IdentityHashMap<FeatureType,Boolean>(8);
@@ -524,11 +521,11 @@
      *
      * @see #OPERATION_INDEX
      */
-    private static boolean isParameterlessOperation(final PropertyType type) {
-        if (type instanceof Operation) {
-            final ParameterDescriptorGroup parameters = ((Operation) type).getParameters();
+    private static boolean isParameterlessOperation(final AbstractIdentifiedType type) {
+        if (type instanceof AbstractOperation) {
+            final ParameterDescriptorGroup parameters = ((AbstractOperation) type).getParameters();
             return ((parameters == null) || parameters.descriptors().isEmpty())
-                   && ((Operation) type).getResult() != null;
+                   && ((AbstractOperation) type).getResult() != null;
         }
         return false;
     }
@@ -543,7 +540,6 @@
      *
      * @return {@code true} if the feature type acts as an abstract super-type.
      */
-    @Override
     public final boolean isAbstract() {
         return isAbstract;
     }
@@ -563,31 +559,22 @@
      *
      * @return {@code true} if this feature type contains only simple attributes or operations.
      */
-    @Override
     public boolean isSimple() {
         return isSimple;
     }
 
     /**
      * Returns {@code true} if the given base type may be the same or a super-type of the given type, using only
-     * the name as a criterion. This is a faster check than {@link #isAssignableFrom(FeatureType)}.
+     * the name as a criterion. This is a faster check than {@link #isAssignableFrom(DefaultFeatureType)}.
      *
      * <p>Performance note: callers should verify that {@code base != type} before to invoke this method.</p>
+     *
+     * <p><b>API note:</b> a non-static method would be more elegant in this "SIS for GeoAPI 3.0" branch.
+     * However this method needs to be static in other SIS branches, because they work with interfaces
+     * rather than SIS implementation. We keep the method static in this branch too for easier merges.</p>
      */
-    static boolean maybeAssignableFrom(final FeatureType base, final FeatureType type) {
-        if (type instanceof DefaultFeatureType) {
-            return ((DefaultFeatureType) type).assignableTo.contains(base.getName());
-        }
-        // Slower path for non-SIS implementations.
-        if (Objects.equals(base.getName(), type.getName())) {
-            return true;
-        }
-        for (final FeatureType superType : type.getSuperTypes()) {
-            if (base == superType || maybeAssignableFrom(base, superType)) {
-                return true;
-            }
-        }
-        return false;
+    static boolean maybeAssignableFrom(final DefaultFeatureType base, final DefaultFeatureType type) {
+        return type.assignableTo.contains(base.getName());
     }
 
     /**
@@ -604,7 +591,7 @@
      * @return {@code true} if instances of the given type can be assigned to association of this type.
      */
     @Override
-    public boolean isAssignableFrom(final FeatureType type) {
+    public boolean isAssignableFrom(final DefaultFeatureType type) {
         if (type == this) {
             return true; // Optimization for a common case.
         }
@@ -616,11 +603,11 @@
          * Ensures that all properties defined in this feature type is also defined
          * in the given property, and that the former is assignable from the later.
          */
-        for (final Map.Entry<String, PropertyType> entry : byName.entrySet()) {
-            final PropertyType other;
+        for (final Map.Entry<String, AbstractIdentifiedType> entry : byName.entrySet()) {
+            final AbstractIdentifiedType other;
             try {
                 other = type.getProperty(entry.getKey());
-            } catch (PropertyNotFoundException e) {
+            } catch (IllegalArgumentException e) {
                 /*
                  * A property in this FeatureType does not exist in the given FeatureType.
                  * Catching exceptions is not an efficient way to perform this check, but
@@ -641,14 +628,18 @@
      * Returns {@code true} if instances of the {@code other} type are assignable to the given {@code base} type.
      * This method does not compare the names — this verification is presumed already done by the caller.
      */
-    private static boolean isAssignableIgnoreName(final PropertyType base, final PropertyType other) {
+    private static boolean isAssignableIgnoreName(final AbstractIdentifiedType base, final AbstractIdentifiedType other) {
         if (base != other) {
-            if (base instanceof AttributeType<?>) {
-                if (!(other instanceof AttributeType<?>)) {
+            /*
+             * Note: other SIS branches use AttributeType and FeatureAssociationRole
+             *       instead than DefaultAttributeType and DefaultAssociationRole.
+             */
+            if (base instanceof DefaultAttributeType<?>) {
+                if (!(other instanceof DefaultAttributeType<?>)) {
                     return false;
                 }
-                final AttributeType<?> p0 = (AttributeType<?>) base;
-                final AttributeType<?> p1 = (AttributeType<?>) other;
+                final DefaultAttributeType<?> p0 = (DefaultAttributeType<?>) base;
+                final DefaultAttributeType<?> p1 = (DefaultAttributeType<?>) other;
                 if (!p0.getValueClass().isAssignableFrom(p1.getValueClass()) ||
                      p0.getMinimumOccurs() > p1.getMinimumOccurs() ||
                      p0.getMaximumOccurs() < p1.getMaximumOccurs())
@@ -656,19 +647,19 @@
                     return false;
                 }
             }
-            if (base instanceof FeatureAssociationRole) {
-                if (!(other instanceof FeatureAssociationRole)) {
+            if (base instanceof DefaultAssociationRole) {
+                if (!(other instanceof DefaultAssociationRole)) {
                     return false;
                 }
-                final FeatureAssociationRole p0 = (FeatureAssociationRole) base;
-                final FeatureAssociationRole p1 = (FeatureAssociationRole) other;
+                final DefaultAssociationRole p0 = (DefaultAssociationRole) base;
+                final DefaultAssociationRole p1 = (DefaultAssociationRole) other;
                 if (p0.getMinimumOccurs() > p1.getMinimumOccurs() ||
                     p0.getMaximumOccurs() < p1.getMaximumOccurs())
                 {
                     return false;
                 }
-                final FeatureType f0 = p0.getValueType();
-                final FeatureType f1 = p1.getValueType();
+                final DefaultFeatureType f0 = p0.getValueType();
+                final DefaultFeatureType f1 = p1.getValueType();
                 if (f0 != f1) {
                     if (!f0.isAssignableFrom(f1)) {
                         return false;
@@ -686,6 +677,10 @@
      * if we compare {@code FeatureType} to {@link Class} in the Java language, then this method is equivalent
      * to {@link Class#getSuperclass()} except that feature types allow multi-inheritance.</div>
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of list elements will be changed to {@code FeatureType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * <div class="note"><b>Note for subclasses:</b>
      * this method is final because it is invoked (indirectly) by constructors, and invoking a user-overrideable
      * method at construction time is not recommended. Furthermore, many Apache SIS methods need guarantees about
@@ -694,9 +689,8 @@
      *
      * @return The parents of this feature type, or an empty set if none.
      */
-    @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public final Set<FeatureType> getSuperTypes() {
+    public final Set<DefaultFeatureType> getSuperTypes() {
         return superTypes;      // Immutable
     }
 
@@ -706,6 +700,10 @@
      * inherited from the {@linkplain #getSuperTypes() super-types} only if {@code includeSuperTypes}
      * is {@code true}.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of list elements will be changed to {@code PropertyType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * <div class="note"><b>Note for subclasses:</b>
      * this method is final because it is invoked (indirectly) by constructors, and invoking a user-overrideable
      * method at construction time is not recommended. Furthermore, many Apache SIS methods need guarantees about
@@ -718,26 +716,29 @@
      *         feature type (not including parent types).
      */
     @Override
-    public final Collection<PropertyType> getProperties(final boolean includeSuperTypes) {
+    public final Collection<AbstractIdentifiedType> getProperties(final boolean includeSuperTypes) {
         return includeSuperTypes ? allProperties : properties;
     }
 
     /**
      * Returns the attribute, operation or association role for the given name.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of returned element will be changed to {@code PropertyType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  name The name of the property to search.
      * @return The property for the given name, or {@code null} if none.
-     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
      *
      * @see AbstractFeature#getProperty(String)
      */
-    @Override
-    public PropertyType getProperty(final String name) throws PropertyNotFoundException {
-        final PropertyType pt = byName.get(name);
+    public AbstractIdentifiedType getProperty(final String name) throws IllegalArgumentException {
+        final AbstractIdentifiedType pt = byName.get(name);
         if (pt != null) {
             return pt;
         }
-        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -757,12 +758,11 @@
      * then this method is equivalent to {@link Class#newInstance()}.</div>
      *
      * @return A new feature instance.
-     * @throws FeatureInstantiationException if this feature type {@linkplain #isAbstract() is abstract}.
+     * @throws IllegalStateException if this feature type {@linkplain #isAbstract() is abstract}.
      */
-    @Override
-    public Feature newInstance() throws FeatureInstantiationException {
+    public AbstractFeature newInstance() throws IllegalStateException {
         if (isAbstract) {
-            throw new FeatureInstantiationException(Errors.format(Errors.Keys.AbstractType_1, getName()));
+            throw new IllegalStateException(Errors.format(Errors.Keys.AbstractType_1, getName()));
         }
         return isSparse ? new SparseFeature(this) : new DenseFeature(this);
     }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java b/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
index 877a9c3..ff9d90e 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
@@ -24,12 +24,6 @@
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.PropertyNotFoundException;
-
 
 /**
  * A feature in which most properties are expected to be provided. This implementation uses a plain array for
@@ -85,14 +79,14 @@
      * @param  name The property name.
      * @return The index for the property of the given name,
      *         or a negative value if the property is a parameterless operation.
-     * @throws PropertyNotFoundException if the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException if the given argument is not a property name of this feature.
      */
-    private int getIndex(final String name) throws PropertyNotFoundException {
+    private int getIndex(final String name) throws IllegalArgumentException {
         final Integer index = indices.get(name);
         if (index != null) {
             return index;
         }
-        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -100,10 +94,10 @@
      *
      * @param  name The property name.
      * @return The property of the given name.
-     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
      */
     @Override
-    public Property getProperty(final String name) throws PropertyNotFoundException {
+    public Object getProperty(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
         final int index = getIndex(name);
         if (index < 0) {
@@ -136,10 +130,10 @@
      *         known to this feature, or if the property can not be set or another reason.
      */
     @Override
-    public void setProperty(final Property property) throws IllegalArgumentException {
+    public void setProperty(final Object property) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("property", property);
-        final String name = property.getName().toString();
-        verifyPropertyType(name, property);
+        final String name = ((Property) property).getName().toString();
+        verifyPropertyType(name, (Property) property);
         if (!(properties instanceof Property[])) {
             wrapValuesInProperties();
         }
@@ -176,10 +170,10 @@
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws PropertyNotFoundException If the given argument is not an attribute or association name of this feature.
+     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
      */
     @Override
-    public Object getPropertyValue(final String name) throws PropertyNotFoundException {
+    public Object getPropertyValue(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
         final int index = getIndex(name);
         if (index < 0) {
@@ -190,10 +184,10 @@
             if (element != null) {
                 if (!(properties instanceof Property[])) {
                     return element; // Most common case.
-                } else if (element instanceof Attribute<?>) {
-                    return getAttributeValue((Attribute<?>) element);
-                } else if (element instanceof FeatureAssociation) {
-                    return getAssociationValue((FeatureAssociation) element);
+                } else if (element instanceof AbstractAttribute<?>) {
+                    return getAttributeValue((AbstractAttribute<?>) element);
+                } else if (element instanceof AbstractAssociation) {
+                    return getAssociationValue((AbstractAssociation) element);
                 } else {
                     throw unsupportedPropertyType(((Property) element).getName());
                 }
@@ -305,10 +299,10 @@
                 for (final Property p : (Property[]) properties) {
                     code = 31 * code;
                     final Object value;
-                    if (p instanceof Attribute<?>) {
-                        value = getAttributeValue((Attribute<?>) p);
-                    } else if (p instanceof FeatureAssociation) {
-                        value = getAssociationValue((FeatureAssociation) p);
+                    if (p instanceof AbstractAttribute<?>) {
+                        value = getAttributeValue((AbstractAttribute<?>) p);
+                    } else if (p instanceof AbstractAssociation) {
+                        value = getAssociationValue((AbstractAssociation) p);
                     } else {
                         continue;
                     }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java
index cc05bc6..b068b5c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java
@@ -37,13 +37,6 @@
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
 import org.apache.sis.internal.jdk8.JDK8;
 import org.apache.sis.internal.jdk7.Objects;
 
@@ -113,7 +106,7 @@
     /**
      * The type of the result returned by the envelope operation.
      */
-    private final AttributeType<Envelope> resultType;
+    private final DefaultAttributeType<Envelope> resultType;
 
     /**
      * Creates a new operation computing the envelope of features of the given type.
@@ -123,7 +116,7 @@
      * @param geometryAttributes the operation or attribute type from which to get geometry values.
      */
     EnvelopeOperation(final Map<String,?> identification, CoordinateReferenceSystem crs,
-            final PropertyType[] geometryAttributes) throws FactoryException
+            final AbstractIdentifiedType[] geometryAttributes) throws FactoryException
     {
         super(identification);
         String defaultGeometry = null;
@@ -138,7 +131,7 @@
          */
         boolean characterizedByCRS = false;
         final Map<String,CoordinateReferenceSystem> names = new LinkedHashMap<String,CoordinateReferenceSystem>(4);
-        for (IdentifiedType property : geometryAttributes) {
+        for (AbstractIdentifiedType property : geometryAttributes) {
             if (AttributeConvention.isGeometryAttribute(property)) {
                 final GenericName name = property.getName();
                 final String attributeName = (property instanceof LinkOperation)
@@ -148,8 +141,8 @@
                     defaultGeometry = attributeName;
                 }
                 CoordinateReferenceSystem attributeCRS = null;
-                while (property instanceof Operation) {
-                    property = ((Operation) property).getResult();
+                while (property instanceof AbstractOperation) {
+                    property = ((AbstractOperation) property).getResult();
                 }
                 /*
                  * At this point 'property' is an attribute, otherwise isGeometryAttribute(property) would have
@@ -157,7 +150,7 @@
                  * have the "CRS" characteristic. Note that we can not rely on 'attributeCRS' being non-null
                  * because an attribute may be characterized by a CRS without providing default CRS.
                  */
-                final AttributeType<?> at = ((AttributeType<?>) property).characteristics().get(characteristicName);
+                final DefaultAttributeType<?> at = ((DefaultAttributeType<?>) property).characteristics().get(characteristicName);
                 if (at != null && CoordinateReferenceSystem.class.isAssignableFrom(at.getValueClass())) {
                     attributeCRS = (CoordinateReferenceSystem) at.getDefaultValue();              // May still null.
                     if (crs == null && isDefault) {
@@ -223,7 +216,7 @@
      * @return an {@code AttributeType<Envelope>}.
      */
     @Override
-    public IdentifiedType getResult() {
+    public AbstractIdentifiedType getResult() {
         return resultType;
     }
 
@@ -248,7 +241,7 @@
      * @return the envelope of geometries in feature property values.
      */
     @Override
-    public Property apply(Feature feature, ParameterValueGroup parameters) {
+    public Property apply(AbstractFeature feature, ParameterValueGroup parameters) {
         return new Result(feature);
     }
 
@@ -268,12 +261,12 @@
         /**
          * The feature specified to the {@link StringJoinOperation#apply(Feature, ParameterValueGroup)} method.
          */
-        private final Feature feature;
+        private final AbstractFeature feature;
 
         /**
          * Creates a new attribute for the given feature.
          */
-        Result(final Feature feature) {
+        Result(final AbstractFeature feature) {
             super(resultType);
             this.feature = feature;
         }
@@ -308,7 +301,7 @@
                      * We do not distinguish which particular property may have a CRS characteristic because SIS 0.7
                      * implementations of DenseFeature and SparseFeature have a "all of nothing" behavior anyway.
                      */
-                    final Property property = feature.getProperty(name);
+                    final Property property = (Property) feature.getProperty(name);
                     genv = Geometries.getEnvelope(property.getValue());
                     if (genv == null) continue;
                     /*
@@ -317,7 +310,7 @@
                      * cases where a CRS characteristic is associated to a particular feature, we will let
                      * Envelopes.transform(…) searches a coordinate operation.
                      */
-                    final Attribute<?> at = ((Attribute<?>) property).characteristics()
+                    final AbstractAttribute<?> at = ((AbstractAttribute<?>) property).characteristics()
                                     .get(AttributeConvention.CRS_CHARACTERISTIC.toString());
                     try {
                         if (at == null) {
@@ -351,7 +344,7 @@
          */
         @Override
         public void setValue(Envelope value) {
-            throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, Attribute.class));
+            throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, AbstractAttribute.class));
         }
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
index 7e7f3ab..1d3f8b1 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
@@ -38,17 +38,6 @@
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.referencing.IdentifiedObjects;
 
-// Branch-dependent imports
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.Operation;
-
 
 /**
  * Formats {@linkplain AbstractFeature features} or {@linkplain DefaultFeatureType feature types} in a tabular format.
@@ -152,13 +141,13 @@
         /*
          * Separate the Feature (optional) and the FeatureType (mandatory) instances.
          */
-        final FeatureType featureType;
-        final Feature feature;
-        if (object instanceof Feature) {
-            feature     = (Feature) object;
+        final DefaultFeatureType featureType;
+        final AbstractFeature feature;
+        if (object instanceof AbstractFeature) {
+            feature     = (AbstractFeature) object;
             featureType = feature.getType();
-        } else if (object instanceof FeatureType) {
-            featureType = (FeatureType) object;
+        } else if (object instanceof DefaultFeatureType) {
+            featureType = (DefaultFeatureType) object;
             feature     = null;
         } else {
             throw new IllegalArgumentException(Errors.getResources(displayLocale)
@@ -169,9 +158,9 @@
          * In none we will ommit the "characteristics" column, which is the last column.
          */
         boolean hasCharacteristics = false;
-        for (final PropertyType propertyType : featureType.getProperties(true)) {
-            if (propertyType instanceof AttributeType<?>) {
-                if (!((AttributeType<?>) propertyType).characteristics().isEmpty()) {
+        for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
+            if (propertyType instanceof DefaultAttributeType<?>) {
+                if (!((DefaultAttributeType<?>) propertyType).characteristics().isEmpty()) {
                     hasCharacteristics = true;
                     break;
                 }
@@ -213,24 +202,17 @@
          */
         final StringBuffer  buffer  = new StringBuffer();
         final FieldPosition dummyFP = new FieldPosition(-1);
-        for (final PropertyType propertyType : featureType.getProperties(true)) {
+        for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
             Object value = null;
             if (feature != null) {
                 value = feature.getPropertyValue(propertyType.getName().toString());
                 if (value == null) {
-                    if (propertyType instanceof AttributeType &&
-                            ((AttributeType) propertyType).getMinimumOccurs() == 0)
-                    {
-                        continue;                                       // If no value, skip the full row.
-                    }
-                    if (propertyType instanceof FeatureAssociationRole &&
-                            ((FeatureAssociationRole) propertyType).getMinimumOccurs() == 0)
-                    {
+                    if (propertyType instanceof FieldType && ((FieldType) propertyType).getMinimumOccurs() == 0) {
                         continue;                                       // If no value, skip the full row.
                     }
                 }
-            } else if (propertyType instanceof AttributeType<?>) {
-                value = ((AttributeType<?>) propertyType).getDefaultValue();
+            } else if (propertyType instanceof DefaultAttributeType<?>) {
+                value = ((DefaultAttributeType<?>) propertyType).getDefaultValue();
             } else if (propertyType instanceof AbstractOperation) {
                 if (((AbstractOperation) propertyType).formatResultFormula(buffer)) {
                     value = CharSequences.trimWhitespaces(buffer).toString();
@@ -248,25 +230,25 @@
             final String   valueType;                       // The value to write in the type column.
             final Class<?> valueClass;                      // AttributeType.getValueClass() if applicable.
             final int minimumOccurs, maximumOccurs;         // Negative values mean no cardinality.
-            final IdentifiedType resultType;                // Result of operation if applicable.
-            if (propertyType instanceof Operation) {
-                resultType = ((Operation) propertyType).getResult();
+            final AbstractIdentifiedType resultType;        // Result of operation if applicable.
+            if (propertyType instanceof AbstractOperation) {
+                resultType = ((AbstractOperation) propertyType).getResult();
             } else {
                 resultType = propertyType;
             }
-            if (resultType instanceof AttributeType<?>) {
-                final AttributeType<?> pt = (AttributeType<?>) resultType;
+            if (resultType instanceof DefaultAttributeType<?>) {
+                final DefaultAttributeType<?> pt = (DefaultAttributeType<?>) resultType;
                 minimumOccurs = pt.getMinimumOccurs();
                 maximumOccurs = pt.getMaximumOccurs();
                 valueClass    = pt.getValueClass();
                 valueType     = getFormat(Class.class).format(valueClass, buffer, dummyFP).toString();
                 buffer.setLength(0);
-            } else if (resultType instanceof FeatureAssociationRole) {
-                final FeatureAssociationRole pt = (FeatureAssociationRole) resultType;
+            } else if (resultType instanceof DefaultAssociationRole) {
+                final DefaultAssociationRole pt = (DefaultAssociationRole) resultType;
                 minimumOccurs = pt.getMinimumOccurs();
                 maximumOccurs = pt.getMaximumOccurs();
                 valueType     = toString(DefaultAssociationRole.getValueTypeName(pt));
-                valueClass    = Feature.class;
+                valueClass    = AbstractFeature.class;
             } else {
                 valueType  = toString(resultType.getName());
                 valueClass = null;
@@ -302,10 +284,10 @@
                     if (value != null) {
                         if (format != null) {
                             value = format.format(value, buffer, dummyFP);
-                        } else if (value instanceof Feature && propertyType instanceof FeatureAssociationRole) {
-                            final String p = DefaultAssociationRole.getTitleProperty((FeatureAssociationRole) propertyType);
+                        } else if (value instanceof AbstractFeature && propertyType instanceof DefaultAssociationRole) {
+                            final String p = DefaultAssociationRole.getTitleProperty((DefaultAssociationRole) propertyType);
                             if (p != null) {
-                                value = ((Feature) value).getPropertyValue(p);
+                                value = ((AbstractFeature) value).getPropertyValue(p);
                                 if (value == null) continue;
                             }
                         }
@@ -320,15 +302,15 @@
              */
             if (hasCharacteristics) {
                 nextColumn(table);
-                if (propertyType instanceof AttributeType<?>) {
+                if (propertyType instanceof DefaultAttributeType<?>) {
                     String separator = "";
-                    for (final AttributeType<?> attribute : ((AttributeType<?>) propertyType).characteristics().values()) {
+                    for (final DefaultAttributeType<?> attribute : ((DefaultAttributeType<?>) propertyType).characteristics().values()) {
                         table.append(separator).append(toString(attribute.getName()));
                         Object c = attribute.getDefaultValue();
                         if (feature != null) {
-                            final Property p = feature.getProperty(propertyType.getName().toString());
-                            if (p instanceof Attribute<?>) {            // Should always be true, but we are paranoiac.
-                                c = ((Attribute<?>) p).characteristics().get(attribute.getName().toString());
+                            final Object p = feature.getProperty(propertyType.getName().toString());
+                            if (p instanceof AbstractAttribute<?>) {      // Should always be true, but we are paranoiac.
+                                c = ((AbstractAttribute<?>) p).characteristics().get(attribute.getName().toString());
                             }
                         }
                         if (c != null) {
@@ -369,8 +351,8 @@
             return ((InternationalString) value).toString(displayLocale);
         } else if (value instanceof GenericName) {
             return toString((GenericName) value);
-        } else if (value instanceof IdentifiedType) {
-            return toString(((IdentifiedType) value).getName());
+        } else if (value instanceof AbstractIdentifiedType) {
+            return toString(((AbstractIdentifiedType) value).getName());
         } else if (value instanceof IdentifiedObject) {
             return IdentifiedObjects.getIdentifierOrName((IdentifiedObject) value);
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
index 3f4e5a7..ed308d3 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
@@ -28,8 +28,6 @@
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
-import org.opengis.feature.Operation;
-import org.opengis.feature.PropertyType;
 
 
 /**
@@ -114,7 +112,7 @@
     /**
      * The pool of operations or operation dependencies created so far, for sharing exiting instances.
      */
-    static final WeakHashSet<PropertyType> POOL = new WeakHashSet<PropertyType>(PropertyType.class);
+    static final WeakHashSet<AbstractIdentifiedType> POOL = new WeakHashSet<AbstractIdentifiedType>(AbstractIdentifiedType.class);
 
     /**
      * Do not allow instantiation of this class.
@@ -151,11 +149,15 @@
      * identified by the {@code referent} argument, the returned property is writable if the referenced
      * property is also writable.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of {@code referent} parameter will be changed to {@code PropertyType}
+     * if and when such interface will be defined in GeoAPI.</div>
+     *
      * @param  identification  the name and other information to be given to the operation.
      * @param  referent        the referenced attribute or feature association.
      * @return an operation which is an alias for the {@code referent} property.
      */
-    public static Operation link(final Map<String,?> identification, final PropertyType referent) {
+    public static AbstractOperation link(final Map<String,?> identification, final AbstractIdentifiedType referent) {
         ArgumentChecks.ensureNonNull("referent", referent);
         return POOL.unique(new LinkOperation(identification, referent));
     }
@@ -186,6 +188,10 @@
      * operation, the given string value will be split around the {@code delimiter} and each substring will be
      * forwarded to the corresponding single property.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of {@code singleAttributes} elements will be changed to {@code PropertyType}
+     * if and when such interface will be defined in GeoAPI.</div>
+     *
      * @param  identification    the name and other information to be given to the operation.
      * @param  delimiter         the characters to use as delimiter between each single property value.
      * @param  prefix            characters to use at the beginning of the concatenated string, or {@code null} if none.
@@ -200,8 +206,8 @@
      *
      * @see <a href="https://en.wikipedia.org/wiki/Compound_key">Compound key on Wikipedia</a>
      */
-    public static Operation compound(final Map<String,?> identification, final String delimiter,
-            final String prefix, final String suffix, final PropertyType... singleAttributes)
+    public static AbstractOperation compound(final Map<String,?> identification, final String delimiter,
+            final String prefix, final String suffix, final AbstractIdentifiedType... singleAttributes)
             throws UnconvertibleObjectException
     {
         ArgumentChecks.ensureNonEmpty("delimiter", delimiter);
@@ -250,6 +256,10 @@
      * This operation is read-only. Calls to {@code Attribute.setValue(Envelope)} will result in an
      * {@link IllegalStateException} to be thrown.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The type of {@code geometryAttributes} elements will be changed to {@code PropertyType}
+     * if and when such interface will be defined in GeoAPI.</div>
+     *
      * @param  identification     the name and other information to be given to the operation.
      * @param  crs                the Coordinate Reference System in which to express the envelope, or {@code null}.
      * @param  geometryAttributes the operation or attribute type from which to get geometry values.
@@ -257,8 +267,8 @@
      * @return an operation which will compute the envelope encompassing all geometries in the given attributes.
      * @throws FactoryException if a coordinate operation to the target CRS can not be created.
      */
-    public static Operation envelope(final Map<String,?> identification, final CoordinateReferenceSystem crs,
-            final PropertyType... geometryAttributes) throws FactoryException
+    public static AbstractOperation envelope(final Map<String,?> identification, final CoordinateReferenceSystem crs,
+            final AbstractIdentifiedType... geometryAttributes) throws FactoryException
     {
         ArgumentChecks.ensureNonNull("geometryAttributes", geometryAttributes);
         return POOL.unique(new EnvelopeOperation(identification, crs, geometryAttributes));
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureType.java
new file mode 100644
index 0000000..5f5e078
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureType.java
@@ -0,0 +1,41 @@
+/*
+ * 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.feature;
+
+import java.util.Collection;
+import org.opengis.util.GenericName;
+
+
+/**
+ * Place-holder for an interface not available in GeoAPI 3.0.
+ * This place-holder will be removed after we upgrade to a later GeoAPI version.
+ *
+ * <p><strong>Do not put this type in public API</strong>. We need to prevent users from using
+ * this type in order to reduce compatibility breaks when we will upgrade the GeoAPI version.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+interface FeatureType {
+    GenericName getName();
+
+    Collection<AbstractIdentifiedType> getProperties(boolean includeSuperTypes);
+
+    boolean isAssignableFrom(DefaultFeatureType type);
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java b/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
index 5692dee..5f4a270 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
@@ -17,7 +17,6 @@
 package org.apache.sis.feature;
 
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.quality.ConformanceResult;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.quality.Element;
@@ -25,12 +24,6 @@
 import org.apache.sis.util.Static;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Static methods working on features or attributes.
@@ -62,7 +55,7 @@
      * @category verification
      */
     @SuppressWarnings("unchecked")
-    public static <V> AttributeType<V> cast(final AttributeType<?> type, final Class<V> valueClass)
+    public static <V> DefaultAttributeType<V> cast(final DefaultAttributeType<?> type, final Class<V> valueClass)
             throws ClassCastException
     {
         if (type != null) {
@@ -74,7 +67,7 @@
                         type.getName(), valueClass, actual));
             }
         }
-        return (AttributeType<V>) type;
+        return (DefaultAttributeType<V>) type;
     }
 
     /**
@@ -91,7 +84,7 @@
      * @category verification
      */
     @SuppressWarnings("unchecked")
-    public static <V> Attribute<V> cast(final Attribute<?> attribute, final Class<V> valueClass)
+    public static <V> AbstractAttribute<V> cast(final AbstractAttribute<?> attribute, final Class<V> valueClass)
             throws ClassCastException
     {
         if (attribute != null) {
@@ -103,7 +96,7 @@
                         attribute.getName(), valueClass, actual));
             }
         }
-        return (Attribute<V>) attribute;
+        return (AbstractAttribute<V>) attribute;
     }
 
     /**
@@ -120,24 +113,13 @@
      * {@code InvalidPropertyValueException} is thrown. Otherwise this method returns doing nothing.
      *
      * @param  feature  the feature to validate, or {@code null}.
-     * @throws InvalidPropertyValueException if the given feature is non-null and does not pass validation.
+     * @throws IllegalArgumentException if the given feature is non-null and does not pass validation.
      *
      * @since 0.7
      */
-    public static void validate(final Feature feature) throws InvalidPropertyValueException {
+    public static void validate(final AbstractFeature feature) throws IllegalArgumentException {
         if (feature != null) {
-            /*
-             * Delegate to AbstractFeature.quality() if possible because the user may have overridden the method.
-             * Otherwise fallback on the same code than AbstractFeature.quality() default implementation.
-             */
-            final DataQuality quality;
-            if (feature instanceof AbstractFeature) {
-                quality = ((AbstractFeature) feature).quality();
-            } else {
-                final Validator v = new Validator(ScopeCode.FEATURE);
-                v.validate(feature.getType(), feature);
-                quality = v.quality;
-            }
+            final DataQuality quality = feature.quality();
             /*
              * Loop on quality elements and check conformance results.
              * NOTE: other types of result are ignored for now, since those other
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java b/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
index 4ecbc39..3e73bf7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
@@ -21,11 +21,6 @@
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.MultiValuedPropertyException;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Base class of property that can be stored in a {@link AbstractFeature} instance.
@@ -36,7 +31,7 @@
  * @version 0.6
  * @module
  */
-abstract class Field<V> implements Property {
+abstract class Field<V> extends Property {
     /**
      * For subclass constructors.
      */
@@ -58,12 +53,12 @@
      * Returns the field feature or attribute value, or {@code null} if none.
      *
      * @return The feature or attribute value (may be {@code null}).
-     * @throws MultiValuedPropertyException if this field contains more than one value.
+     * @throws IllegalStateException if this field contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract V getValue() throws MultiValuedPropertyException;
+    public abstract V getValue() throws IllegalStateException;
 
     /**
      * Returns all features or attribute values, or an empty collection if none.
@@ -92,16 +87,16 @@
      * then delegates to {@link #setValue(Object)}.</p>
      *
      * @param values The new values.
-     * @throws InvalidPropertyValueException if the given collection contains too many elements.
+     * @throws IllegalArgumentException if the given collection contains too many elements.
      */
-    public void setValues(final Collection<? extends V> values) throws InvalidPropertyValueException {
+    public void setValues(final Collection<? extends V> values) throws IllegalArgumentException {
         V value = null;
         ArgumentChecks.ensureNonNull("values", values);
         final Iterator<? extends V> it = values.iterator();
         if (it.hasNext()) {
             value = it.next();
             if (it.hasNext()) {
-                throw new InvalidPropertyValueException(Errors.format(Errors.Keys.TooManyOccurrences_2, 1, getName()));
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.TooManyOccurrences_2, 1, getName()));
             }
         }
         setValue(value);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
index 9d7d929..7eda0e7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/FieldType.java
@@ -21,9 +21,6 @@
 import org.opengis.util.GenericName;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-
 
 /**
  * Base class of property types having a value and a cardinality.
@@ -39,7 +36,7 @@
  * @version 0.5
  * @module
  */
-abstract class FieldType extends AbstractIdentifiedType implements PropertyType {
+abstract class FieldType extends AbstractIdentifiedType {
     /**
      * For cross-version compatibility.
      */
@@ -134,7 +131,7 @@
      * @param type      The property type, sometime {@code this} or sometime an other object.
      * @param valueType The name of value class (attribute), or the feature type name (association).
      */
-    static StringBuilder toString(final String className, final PropertyType type, final Object valueType) {
+    static StringBuilder toString(final String className, final AbstractIdentifiedType type, final Object valueType) {
         final StringBuilder buffer = new StringBuilder(40).append(className).append('[');
         final GenericName name = type.getName();
         if (name != null) {
@@ -160,7 +157,9 @@
      * @param valueType The name of value class (attribute), or the feature type name (association).
      * @param values    The actual values.
      */
-    static StringBuilder toString(final String className, final PropertyType type, final Object valueType, final Iterator<?> values) {
+    static StringBuilder toString(final String className, final AbstractIdentifiedType type,
+            final Object valueType, final Iterator<?> values)
+    {
         final StringBuilder buffer = toString(className, type, valueType);
         if (values.hasNext()) {
             final Object value = values.next();
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/InvalidFeatureException.java b/core/sis-feature/src/main/java/org/apache/sis/feature/InvalidFeatureException.java
index 055feb3..a12e155 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/InvalidFeatureException.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/InvalidFeatureException.java
@@ -20,10 +20,6 @@
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.util.LocalizedException;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Thrown when a feature fails at least one conformance test.
@@ -39,7 +35,7 @@
  *
  * @see Features#validate(Feature)
  */
-final class InvalidFeatureException extends InvalidPropertyValueException implements LocalizedException {
+final class InvalidFeatureException extends IllegalArgumentException implements LocalizedException {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
index afad3d5..d6e75f8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
@@ -31,10 +31,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.UncheckedIOException;
-import org.opengis.feature.Feature;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
 
 
 /**
@@ -79,7 +75,7 @@
     /**
      * The type of the result.
      */
-    private final PropertyType result;
+    private final AbstractIdentifiedType result;
 
     /**
      * The name of the referenced attribute or feature association.
@@ -94,7 +90,7 @@
      *
      * @see FeatureOperations#link(Map, PropertyType)
      */
-    LinkOperation(final Map<String,?> identification, final PropertyType referent) {
+    LinkOperation(final Map<String,?> identification, final AbstractIdentifiedType referent) {
         super(identification);
         result = referent;
         referentName = referent.getName().toString();
@@ -112,7 +108,7 @@
      * Returns the expected result type.
      */
     @Override
-    public IdentifiedType getResult() {
+    public AbstractIdentifiedType getResult() {
         return result;
     }
 
@@ -132,7 +128,7 @@
      * @return the linked property from the given feature.
      */
     @Override
-    public Property apply(final Feature feature, final ParameterValueGroup parameters) {
+    public Object apply(final AbstractFeature feature, final ParameterValueGroup parameters) {
         ArgumentChecks.ensureNonNull("feature", feature);
         return feature.getProperty(referentName);
     }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
index d946dd1..114c787 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
@@ -21,12 +21,6 @@
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.MultiValuedPropertyException;
-
 
 /**
  * An instance of an {@linkplain DefaultAssociationRole association role} containing an arbitrary amount of values.
@@ -59,16 +53,16 @@
     /**
      * The association values.
      */
-    private CheckedArrayList<Feature> values;
+    private CheckedArrayList<AbstractFeature> values;
 
     /**
      * Creates a new association of the given role.
      *
      * @param role Information about the association.
      */
-    public MultiValuedAssociation(final FeatureAssociationRole role) {
+    public MultiValuedAssociation(final DefaultAssociationRole role) {
         super(role);
-        values = new CheckedArrayList<Feature>(Feature.class);
+        values = new CheckedArrayList<AbstractFeature>(AbstractFeature.class);
     }
 
     /**
@@ -77,12 +71,12 @@
      * @param role   Information about the association.
      * @param values The initial values, or {@code null} for initializing to an empty list.
      */
-    MultiValuedAssociation(final FeatureAssociationRole role, final Object values) {
+    MultiValuedAssociation(final DefaultAssociationRole role, final Object values) {
         super(role);
         if (values == null) {
-            this.values = new CheckedArrayList<Feature>(Feature.class);
+            this.values = new CheckedArrayList<AbstractFeature>(AbstractFeature.class);
         } else {
-            this.values = CheckedArrayList.castOrCopy((CheckedArrayList<?>) values, Feature.class);
+            this.values = CheckedArrayList.castOrCopy((CheckedArrayList<?>) values, AbstractFeature.class);
         }
     }
 
@@ -90,14 +84,14 @@
      * Returns the feature, or {@code null} if none.
      *
      * @return The feature (may be {@code null}).
-     * @throws MultiValuedPropertyException if this association contains more than one value.
+     * @throws IllegalStateException if this association contains more than one value.
      */
     @Override
-    public Feature getValue() {
+    public AbstractFeature getValue() {
         switch (values.size()) {
             case 0:  return null;
             case 1:  return values.get(0);
-            default: throw new MultiValuedPropertyException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
+            default: throw new IllegalStateException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
         }
     }
 
@@ -109,7 +103,7 @@
      * @return The features in a <cite>live</cite> collection.
      */
     @Override
-    public Collection<Feature> getValues() {
+    public Collection<AbstractFeature> getValues() {
         return values;
     }
 
@@ -119,7 +113,7 @@
      * @param value The new value, or {@code null} for removing all values from this association.
      */
     @Override
-    public void setValue(final Feature value) {
+    public void setValue(final AbstractFeature value) {
         values.clear();
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());
@@ -133,12 +127,12 @@
      * @param newValues The new values.
      */
     @Override
-    public void setValues(final Collection<? extends Feature> newValues) {
+    public void setValues(final Collection<? extends AbstractFeature> newValues) {
         if (newValues != values) {
             ArgumentChecks.ensureNonNull("values", newValues);  // The parameter name in public API is "values".
-            final FeatureType base = role.getValueType();
+            final DefaultFeatureType base = role.getValueType();
             values.clear();
-            for (final Feature value : newValues) {
+            for (final AbstractFeature value : newValues) {
                 ensureValid(base, value.getType());
                 values.add(value);
             }
@@ -157,7 +151,7 @@
     @SuppressWarnings("unchecked")
     public MultiValuedAssociation clone() throws CloneNotSupportedException {
         final MultiValuedAssociation clone = (MultiValuedAssociation) super.clone();
-        clone.values = (CheckedArrayList<Feature>) clone.values.clone();
+        clone.values = (CheckedArrayList<AbstractFeature>) clone.values.clone();
         return clone;
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java b/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
index e7dfc51..1d5c3b6 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
@@ -22,10 +22,6 @@
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.MultiValuedPropertyException;
-
 
 /**
  * An instance of an {@linkplain DefaultAttributeType attribute type} containing an arbitrary amount of values.
@@ -69,7 +65,7 @@
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    public MultiValuedAttribute(final AttributeType<V> type) {
+    public MultiValuedAttribute(final DefaultAttributeType<V> type) {
         super(type);
         values = new CheckedArrayList<V>(type.getValueClass());
         final V value = type.getDefaultValue();
@@ -86,7 +82,7 @@
      * @param values The initial values, or {@code null} for initializing to an empty list.
      */
     @SuppressWarnings("unchecked")
-    MultiValuedAttribute(final AttributeType<V> type, final Object values) {
+    MultiValuedAttribute(final DefaultAttributeType<V> type, final Object values) {
         super(type);
         final Class<V> valueClass = type.getValueClass();
         if (values == null) {
@@ -105,14 +101,14 @@
      * Returns the attribute value, or {@code null} if none.
      *
      * @return The attribute value (may be {@code null}).
-     * @throws MultiValuedPropertyException if this attribute contains more than one value.
+     * @throws IllegalStateException if this attribute contains more than one value.
      */
     @Override
     public V getValue() {
         switch (values.size()) {
             case 0:  return null;
             case 1:  return values.get(0);
-            default: throw new MultiValuedPropertyException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
+            default: throw new IllegalStateException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
         }
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java b/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
index e4207f1..2b2af09 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
@@ -16,18 +16,10 @@
  */
 package org.apache.sis.feature;
 
-import java.util.Set;
 import java.util.Collection;
 import java.util.Collections;
 import java.io.Serializable;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.PropertyNotFoundException;
-import org.opengis.feature.FeatureInstantiationException;
 import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
-import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -66,48 +58,11 @@
         return name;
     }
 
-    /** Undefined. */ @Override public InternationalString getDefinition()  {return null;}
-    /** Undefined. */ @Override public InternationalString getDesignation() {return null;}
-    /** Undefined. */ @Override public InternationalString getDescription() {return null;}
-
-    /**
-     * Declares that this feature shall not be instantiated.
-     */
-    @Override
-    public boolean isAbstract() {
-        return true;
-    }
-
-    /**
-     * Conservatively assumes that the feature is not simple,
-     * since we do not know what the actual feature will be.
-     */
-    @Override
-    public boolean isSimple() {
-        return false;
-    }
-
-    /**
-     * Always throws {@link PropertyNotFoundException} since this feature type has no declared property yet.
-     */
-    @Override
-    public PropertyType getProperty(final String name) throws PropertyNotFoundException {
-        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
-    }
-
     /**
      * Returns an empty set since this feature has no declared property yet.
      */
     @Override
-    public Collection<? extends PropertyType> getProperties(final boolean includeSuperTypes) {
-        return Collections.emptySet();
-    }
-
-    /**
-     * Returns an empty set since this feature has no declared parent yet.
-     */
-    @Override
-    public Set<? extends FeatureType> getSuperTypes() {
+    public Collection<AbstractIdentifiedType> getProperties(final boolean includeSuperTypes) {
         return Collections.emptySet();
     }
 
@@ -115,16 +70,8 @@
      * This feature type is considered independent of all other feature types except itself.
      */
     @Override
-    public boolean isAssignableFrom(final FeatureType type) {
-        return (type instanceof NamedFeatureType);
-    }
-
-    /**
-     * Unsupported operation, since the feature has not yet been resolved.
-     */
-    @Override
-    public Feature newInstance() throws FeatureInstantiationException {
-        throw new FeatureInstantiationException(Errors.format(Errors.Keys.UnresolvedFeatureName_1, getName()));
+    public boolean isAssignableFrom(final DefaultFeatureType type) {
+        return false;
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/Property.java b/core/sis-feature/src/main/java/org/apache/sis/feature/Property.java
new file mode 100644
index 0000000..00b4ff3
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Property.java
@@ -0,0 +1,38 @@
+/*
+ * 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.feature;
+
+import org.opengis.util.GenericName;
+
+
+/**
+ * Place-holder for an interface not available in GeoAPI 3.0.
+ * This place-holder will be removed after we upgrade to a later GeoAPI version.
+ *
+ * <p><strong>Do not put this type in public API</strong>. We need to prevent users from using
+ * this type in order to reduce compatibility breaks when we will upgrade the GeoAPI version.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+abstract class Property {
+    public abstract GenericName getName();
+
+    public abstract Object getValue();
+}
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
index 9e68dd6..523d536 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
@@ -18,9 +18,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.InvalidPropertyValueException;
 
 
 /**
@@ -51,14 +48,14 @@
     /**
      * The associated feature.
      */
-    private Feature value;
+    private AbstractFeature value;
 
     /**
      * Creates a new association of the given role.
      *
      * @param role Information about the association.
      */
-    public SingletonAssociation(final FeatureAssociationRole role) {
+    public SingletonAssociation(final DefaultAssociationRole role) {
         super(role);
         assert isSingleton(role.getMaximumOccurs());
     }
@@ -69,7 +66,7 @@
      * @param role  Information about the association.
      * @param value The initial value (may be {@code null}).
      */
-    SingletonAssociation(final FeatureAssociationRole role, final Feature value) {
+    SingletonAssociation(final DefaultAssociationRole role, final AbstractFeature value) {
         super(role);
         assert isSingleton(role.getMaximumOccurs());
         this.value = value;
@@ -84,7 +81,7 @@
      * @return The associated feature (may be {@code null}).
      */
     @Override
-    public Feature getValue() {
+    public AbstractFeature getValue() {
         return value;
     }
 
@@ -92,10 +89,10 @@
      * Sets the associated feature.
      *
      * @param  value The new value, or {@code null}.
-     * @throws InvalidPropertyValueException If the given feature is not valid for this association.
+     * @throws IllegalArgumentException If the given feature is not valid for this association.
      */
     @Override
-    public void setValue(final Feature value) throws InvalidPropertyValueException {
+    public void setValue(final AbstractFeature value) throws IllegalArgumentException {
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java b/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
index a7389e5..69ab8a2 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAttribute.java
@@ -18,7 +18,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.AttributeType;
 
 
 /**
@@ -60,7 +59,7 @@
      *
      * @param type Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      */
-    public SingletonAttribute(final AttributeType<V> type) {
+    public SingletonAttribute(final DefaultAttributeType<V> type) {
         super(type);
         assert isSingleton(type.getMaximumOccurs());
         value = type.getDefaultValue();
@@ -73,7 +72,7 @@
      * @param type  Information about the attribute (base Java class, domain of values, <i>etc.</i>).
      * @param value The initial value (may be {@code null}).
      */
-    SingletonAttribute(final AttributeType<V> type, final Object value) {
+    SingletonAttribute(final DefaultAttributeType<V> type, final Object value) {
         super(type);
         assert isSingleton(type.getMaximumOccurs());
         this.value = type.getValueClass().cast(value);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java b/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
index ebd60d4..7eba3f6 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
@@ -28,10 +28,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.Property;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -120,14 +116,14 @@
      * @param  name The property name.
      * @return The index for the property of the given name,
      *         or a negative value if the property is a parameterless operation.
-     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
      */
-    private int getIndex(final String name) throws PropertyNotFoundException {
+    private int getIndex(final String name) throws IllegalArgumentException {
         final Integer index = indices.get(name);
         if (index != null) {
             return index;
         }
-        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -172,10 +168,10 @@
      *
      * @param  name The property name.
      * @return The property of the given name.
-     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
+     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
      */
     @Override
-    public Property getProperty(final String name) throws PropertyNotFoundException {
+    public Object getProperty(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
         requireMapOfProperties();
         return getPropertyInstance(name);
@@ -185,11 +181,11 @@
      * Implementation of {@link #getProperty(String)} invoked when we know that the {@link #properties}
      * map contains {@code Property} instances (as opposed to their value).
      */
-    private Property getPropertyInstance(final String name) throws PropertyNotFoundException {
+    private Property getPropertyInstance(final String name) throws IllegalArgumentException {
         assert valuesKind == PROPERTIES : valuesKind;
         final Integer index = getIndex(name);
         if (index < 0) {
-            return getOperationResult(name);
+            return (Property) getOperationResult(name);
         }
         Property property = (Property) properties.get(index);
         if (property == null) {
@@ -207,10 +203,10 @@
      *         known to this feature, or if the property can not be set for another reason.
      */
     @Override
-    public void setProperty(final Property property) throws IllegalArgumentException {
+    public void setProperty(final Object property) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("property", property);
-        final String name = property.getName().toString();
-        verifyPropertyType(name, property);
+        final String name = ((Property) property).getName().toString();
+        verifyPropertyType(name, (Property) property);
         requireMapOfProperties();
         /*
          * Following index should never be OPERATION_INDEX (a negative value) because the call
@@ -224,10 +220,10 @@
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws PropertyNotFoundException If the given argument is not an attribute or association name of this feature.
+     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
      */
     @Override
-    public Object getPropertyValue(final String name) throws PropertyNotFoundException {
+    public Object getPropertyValue(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
         final Integer index = getIndex(name);
         if (index < 0) {
@@ -237,10 +233,10 @@
         if (element != null) {
             if (valuesKind == VALUES) {
                 return element; // Most common case.
-            } else if (element instanceof Attribute<?>) {
-                return getAttributeValue((Attribute<?>) element);
-            } else if (element instanceof FeatureAssociation) {
-                return getAssociationValue((FeatureAssociation) element);
+            } else if (element instanceof AbstractAttribute<?>) {
+                return getAttributeValue((AbstractAttribute<?>) element);
+            } else if (element instanceof AbstractAssociation) {
+                return getAssociationValue((AbstractAssociation) element);
             } else if (valuesKind == PROPERTIES) {
                 throw unsupportedPropertyType(((Property) element).getName());
             } else {
@@ -375,10 +371,10 @@
             for (final Map.Entry<Integer,Object> entry : properties.entrySet()) {
                 final Object p = entry.getValue();
                 final Object value;
-                if (p instanceof Attribute<?>) {
-                    value = getAttributeValue((Attribute<?>) p);
-                } else if (p instanceof FeatureAssociation) {
-                    value = getAssociationValue((FeatureAssociation) p);
+                if (p instanceof AbstractAttribute<?>) {
+                    value = getAttributeValue((AbstractAttribute<?>) p);
+                } else if (p instanceof AbstractAssociation) {
+                    value = getAssociationValue((AbstractAssociation) p);
                 } else {
                     value = null;
                 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java b/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
index 54ee9e9..1767956 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
@@ -35,13 +35,6 @@
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
 import org.apache.sis.internal.jdk8.UncheckedIOException;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
 
 
 /**
@@ -101,7 +94,7 @@
     /**
      * The type of the result returned by the string concatenation operation.
      */
-    private final AttributeType<String> resultType;
+    private final DefaultAttributeType<String> resultType;
 
     /**
      * The characters to use at the beginning of the concatenated string, or an empty string if none.
@@ -127,7 +120,7 @@
      */
     @SuppressWarnings({"rawtypes", "unchecked"})                                        // Generic array creation.
     StringJoinOperation(final Map<String,?> identification, final String delimiter,
-            final String prefix, final String suffix, final PropertyType[] singleAttributes)
+            final String prefix, final String suffix, final AbstractIdentifiedType[] singleAttributes)
             throws UnconvertibleObjectException
     {
         super(identification);
@@ -140,18 +133,18 @@
              *   - properties are either attributes, or operations producing attributes.
              *   - attributes contain at most one value (no collections).
              */
-            IdentifiedType attributeType = singleAttributes[i];
+            AbstractIdentifiedType attributeType = singleAttributes[i];
             ArgumentChecks.ensureNonNullElement("singleAttributes", i, attributeType);
             final GenericName name = attributeType.getName();
-            if (attributeType instanceof Operation) {
-                attributeType = ((Operation) attributeType).getResult();
+            if (attributeType instanceof AbstractOperation) {
+                attributeType = ((AbstractOperation) attributeType).getResult();
             }
-            if (!(attributeType instanceof AttributeType)) {
+            if (!(attributeType instanceof DefaultAttributeType)) {
                 throw new IllegalArgumentException(Errors.getResources(identification)
                         .getString(Errors.Keys.IllegalPropertyType_2, name,
-                        Classes.getLeafInterfaces(attributeType.getClass(), PropertyType.class)[0]));
+                        Classes.getLeafInterfaces(attributeType.getClass(), AbstractIdentifiedType.class)[0]));
             }
-            if (((AttributeType<?>) attributeType).getMaximumOccurs() > 1) {
+            if (((DefaultAttributeType<?>) attributeType).getMaximumOccurs() > 1) {
                 throw new IllegalArgumentException(Errors.getResources(identification)
                         .getString(Errors.Keys.NotASingleton_1, name));
             }
@@ -160,7 +153,7 @@
              * We need only their names and how to convert from String to their values.
              */
             attributeNames[i] = name.toString();
-            converters[i] = ObjectConverters.find(String.class, ((AttributeType<?>) attributeType).getValueClass());
+            converters[i] = ObjectConverters.find(String.class, ((DefaultAttributeType<?>) attributeType).getValueClass());
         }
         resultType = FeatureOperations.POOL.unique(new DefaultAttributeType<String>(
                 resultIdentification(identification), String.class, 1, 1, null));
@@ -187,7 +180,7 @@
      * @return an {@code AttributeType<String>}.
      */
     @Override
-    public IdentifiedType getResult() {
+    public AbstractIdentifiedType getResult() {
         return resultType;
     }
 
@@ -223,7 +216,7 @@
      * @return the concatenation of feature property values.
      */
     @Override
-    public Property apply(Feature feature, ParameterValueGroup parameters) {
+    public Property apply(AbstractFeature feature, ParameterValueGroup parameters) {
         ArgumentChecks.ensureNonNull("feature", feature);
         return new Result(feature);
     }
@@ -244,12 +237,12 @@
         /**
          * The feature specified to the {@link StringJoinOperation#apply(Feature, ParameterValueGroup)} method.
          */
-        private final Feature feature;
+        private final AbstractFeature feature;
 
         /**
          * Creates a new attribute for the given feature.
          */
-        Result(final Feature feature) {
+        Result(final AbstractFeature feature) {
             super(resultType);
             this.feature = feature;
         }
@@ -312,11 +305,11 @@
          * @throws InvalidPropertyValueException if one of the attribute values can not be parsed to the expected type.
          */
         @Override
-        public void setValue(final String value) throws InvalidPropertyValueException {
+        public void setValue(final String value) throws IllegalArgumentException {
             final int endAt = value.length() - suffix.length();
             final boolean prefixMatches = value.startsWith(prefix);
             if (!prefixMatches || !value.endsWith(suffix)) {
-                throw new InvalidPropertyValueException(Errors.format(Errors.Keys.UnexpectedCharactersAtBound_4,
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.UnexpectedCharactersAtBound_4,
                         getName(),
                         prefixMatches ? 1 : 0,              // For "{1,choice,0#begin|1#end}" in message format.
                         prefixMatches ? suffix : prefix,
@@ -378,7 +371,7 @@
                 if (!element.isEmpty() && count < values.length) try {
                     values[count] = converters[count].apply(element);
                 } catch (UnconvertibleObjectException e) {
-                    throw new InvalidPropertyValueException(Errors.format(
+                    throw new IllegalArgumentException(Errors.format(
                             Errors.Keys.CanNotAssign_2, attributeNames[count], element), e);
                 }
                 count++;
@@ -390,7 +383,7 @@
              * in order to have a "all or nothing" behavior.
              */
             if (values.length != count) {
-                throw new InvalidPropertyValueException(
+                throw new IllegalArgumentException(
                         Errors.format(Errors.Keys.UnexpectedNumberOfComponents_3, value, values.length, count));
             }
             for (int i=0; i < values.length; i++) {
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 62b976c..684d85c 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
@@ -32,16 +32,6 @@
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.util.resources.Errors;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.FeatureAssociationRole;
-
 
 /**
  * Provides validation methods to be shared by different implementations.
@@ -88,7 +78,7 @@
      * @return The {@code report}, or a new report if {@code report} was null.
      */
     private AbstractElement addViolationReport(AbstractElement report,
-            final PropertyType type, final InternationalString explanation)
+            final AbstractIdentifiedType type, final InternationalString explanation)
     {
         if (report == null) {
             final GenericName name = type.getName();
@@ -119,19 +109,19 @@
      * @param type     the type of the {@code feature} argument, provided explicitely for protecting from user overriding.
      * @param feature  the feature to validate.
      */
-    void validate(final FeatureType type, final Feature feature) {
-        for (final PropertyType pt : type.getProperties(true)) {
-            final Property property = feature.getProperty(pt.getName().toString());
+    void validate(final FeatureType type, final AbstractFeature feature) {
+        for (final AbstractIdentifiedType pt : type.getProperties(true)) {
+            final Object property = feature.getProperty(pt.getName().toString());
             final DataQuality pq;
             if (property instanceof AbstractAttribute<?>) {
                 pq = ((AbstractAttribute<?>) property).quality();
             } else if (property instanceof AbstractAssociation) {
                 pq = ((AbstractAssociation) property).quality();
-            } else if (property instanceof Attribute<?>) {
-                validateAny(((Attribute<?>) property).getType(), ((Attribute<?>) property).getValues());
+            } else if (property instanceof AbstractAttribute<?>) {
+                validateAny(((AbstractAttribute<?>) property).getType(), ((AbstractAttribute<?>) property).getValues());
                 continue;
-            } else if (property instanceof FeatureAssociation) {
-                validateAny(((FeatureAssociation) property).getRole(), ((FeatureAssociation) property).getValues());
+            } else if (property instanceof AbstractAssociation) {
+                validateAny(((AbstractAssociation) property).getRole(), ((AbstractAssociation) property).getValues());
                 continue;
             } else {
                 continue;
@@ -146,21 +136,21 @@
      * Verifies if the given value is valid for the given attribute type.
      * This method delegates to one of the {@code validate(…)} methods depending of the value type.
      */
-    void validateAny(final PropertyType type, final Object value) {
-        if (type instanceof AttributeType<?>) {
-            validate((AttributeType<?>) type, asList(value,
-                    ((AttributeType<?>) type).getMaximumOccurs()));
+    void validateAny(final AbstractIdentifiedType type, final Object value) {
+        if (type instanceof DefaultAttributeType<?>) {
+            validate((DefaultAttributeType<?>) type, asList(value,
+                    ((DefaultAttributeType<?>) type).getMaximumOccurs()));
         }
-        if (type instanceof FeatureAssociationRole) {
-            validate((FeatureAssociationRole) type, asList(value,
-                    ((FeatureAssociationRole) type).getMaximumOccurs()));
+        if (type instanceof DefaultAssociationRole) {
+            validate((DefaultAssociationRole) type, asList(value,
+                    ((DefaultAssociationRole) type).getMaximumOccurs()));
         }
     }
 
     /**
      * Verifies if the given values are valid for the given attribute type.
      */
-    void validate(final AttributeType<?> type, final Collection<?> values) {
+    void validate(final DefaultAttributeType<?> type, final Collection<?> values) {
         AbstractElement report = null;
         for (final Object value : values) {
             /*
@@ -183,10 +173,10 @@
     /**
      * Verifies if the given value is valid for the given association role.
      */
-    void validate(final FeatureAssociationRole role, final Collection<?> values) {
+    void validate(final DefaultAssociationRole role, final Collection<?> values) {
         AbstractElement report = null;
         for (final Object value : values) {
-            final FeatureType type = ((Feature) value).getType();
+            final DefaultFeatureType type = ((AbstractFeature) value).getType();
             final FeatureType valueType = role.getValueType();
             if (!valueType.isAssignableFrom(type)) {
                 report = addViolationReport(report, role, Errors.formatInternational(
@@ -204,7 +194,7 @@
      *
      * @param report Where to add the result, or {@code null} if not yet created.
      */
-    private void verifyCardinality(final AbstractElement report, final PropertyType type,
+    private void verifyCardinality(final AbstractElement report, final AbstractIdentifiedType type,
             final int minimumOccurs, final int maximumOccurs, final int count)
     {
         if (count < minimumOccurs) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AssociationRoleBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AssociationRoleBuilder.java
index 6a9ba54..ad855a7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AssociationRoleBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AssociationRoleBuilder.java
@@ -20,9 +20,8 @@
 import org.apache.sis.feature.DefaultAssociationRole;
 
 // Branch-dependent imports
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.FeatureAssociationRole;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.DefaultFeatureType;
 
 
 /**
@@ -45,7 +44,7 @@
     /**
      * The target feature type, or {@code null} if unknown.
      */
-    private final FeatureType type;
+    private final DefaultFeatureType type;
 
     /**
      * Name of the target feature type (never null).
@@ -58,7 +57,7 @@
      *
      * @param owner  the builder of the {@code FeatureType} for which to add this property.
      */
-    AssociationRoleBuilder(final FeatureTypeBuilder owner, final FeatureType type, final GenericName typeName) {
+    AssociationRoleBuilder(final FeatureTypeBuilder owner, final DefaultFeatureType type, final GenericName typeName) {
         super(owner, null);
         this.type     = type;
         this.typeName = typeName;
@@ -69,7 +68,7 @@
      *
      * @param owner  the builder of the {@code FeatureType} for which to add this property.
      */
-    AssociationRoleBuilder(final FeatureTypeBuilder owner, final FeatureAssociationRole template) {
+    AssociationRoleBuilder(final FeatureTypeBuilder owner, final DefaultAssociationRole template) {
         super(owner, template);
         minimumOccurs = template.getMinimumOccurs();
         maximumOccurs = template.getMaximumOccurs();
@@ -167,7 +166,7 @@
      * Creates a new property type from the current setting.
      */
     @Override
-    final PropertyType create() {
+    final AbstractIdentifiedType create() {
         if (type != null) {
             return new DefaultAssociationRole(identification(), type, minimumOccurs, maximumOccurs);
         } else {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AttributeTypeBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AttributeTypeBuilder.java
index e5d1abf..a32d01d 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AttributeTypeBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/AttributeTypeBuilder.java
@@ -31,8 +31,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.PropertyType;
+import org.apache.sis.feature.AbstractIdentifiedType;
 
 
 /**
@@ -88,13 +87,13 @@
      *
      * @param owner  the builder of the {@code FeatureType} for which to add this property.
      */
-    AttributeTypeBuilder(final FeatureTypeBuilder owner, final AttributeType<V> template) {
+    AttributeTypeBuilder(final FeatureTypeBuilder owner, final DefaultAttributeType<V> template) {
         super(owner, template);
         minimumOccurs = template.getMinimumOccurs();
         maximumOccurs = template.getMaximumOccurs();
         valueClass    = template.getValueClass();
         defaultValue  = template.getDefaultValue();
-        for (final AttributeType<?> c : template.characteristics().values()) {
+        for (final DefaultAttributeType<?> c : template.characteristics().values()) {
             characteristics.add(new CharacteristicTypeBuilder(this, c));
         }
     }
@@ -264,13 +263,17 @@
      * Adds another attribute type that describes this attribute type, using an existing one as a template.
      * See <cite>"Attribute characterization"</cite> in {@link DefaultAttributeType} Javadoc for more information.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code template} argument type will be changed to {@code AttributeType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  <C>       the compile-time type of values in the {@code template} argument.
      * @param  template  an existing attribute type to use as a template.
      * @return a builder for a characteristic of this attribute, initialized with the values of the given template.
      *
      * @see #characteristics()
      */
-    public <C> CharacteristicTypeBuilder<C> addCharacteristic(final AttributeType<C> template) {
+    public <C> CharacteristicTypeBuilder<C> addCharacteristic(final DefaultAttributeType<C> template) {
         ensureNonNull("template", template);
         final CharacteristicTypeBuilder<C> characteristic = new CharacteristicTypeBuilder<C>(this, template);
         characteristics.add(characteristic);
@@ -375,8 +378,8 @@
      * Creates a new property type from the current setting.
      */
     @Override
-    final PropertyType create() {
-        final AttributeType<?>[] chrts = new AttributeType<?>[characteristics.size()];
+    final AbstractIdentifiedType create() {
+        final DefaultAttributeType<?>[] chrts = new DefaultAttributeType<?>[characteristics.size()];
         for (int i=0; i<chrts.length; i++) {
             chrts[i] = characteristics.get(i).build();
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/CharacteristicTypeBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/CharacteristicTypeBuilder.java
index 5cbe8f5..7601fba 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/CharacteristicTypeBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/CharacteristicTypeBuilder.java
@@ -22,7 +22,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.AttributeType;
 
 
 /**
@@ -63,7 +62,7 @@
      * The characteristic created by this builder, or {@code null} if not yet created.
      * This field must be cleared every time that a setter method is invoked on this builder.
      */
-    private transient AttributeType<V> characteristic;
+    private transient DefaultAttributeType<V> characteristic;
 
     /**
      * Creates a new characteristic builder for values of the given class.
@@ -82,7 +81,7 @@
      *
      * @param owner  the builder of the {@code AttributeType} for which to add this property.
      */
-    CharacteristicTypeBuilder(final AttributeTypeBuilder<?> owner, final AttributeType<V> template) {
+    CharacteristicTypeBuilder(final AttributeTypeBuilder<?> owner, final DefaultAttributeType<V> template) {
         super(template, owner.getLocale());
         this.owner     = owner;
         valueClass     = template.getValueClass();
@@ -210,7 +209,7 @@
     /**
      * Creates a new characteristic from the current setting.
      */
-    final AttributeType<V> build() {
+    final DefaultAttributeType<V> build() {
         if (characteristic == null) {
             characteristic = new DefaultAttributeType<V>(identification(), valueClass, 0, 1, defaultValue);
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java
index 082aaf6..90fdafb 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java
@@ -37,11 +37,10 @@
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.JDK7;
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.FeatureAssociationRole;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.DefaultAssociationRole;
+import org.apache.sis.feature.DefaultAttributeType;
 
 
 /**
@@ -75,7 +74,7 @@
     /**
      * The parent of the feature to create. By default, new features have no parent.
      */
-    private final List<FeatureType> superTypes;
+    private final List<DefaultFeatureType> superTypes;
 
     /**
      * Whether the feature type is abstract. The default value is {@code false}.
@@ -139,7 +138,7 @@
      * The object created by this builder, or {@code null} if not yet created.
      * This field must be cleared every time that a setter method is invoked on this builder.
      */
-    private transient FeatureType feature;
+    private transient DefaultFeatureType feature;
 
     /**
      * Creates a new builder instance using the default name factory.
@@ -151,27 +150,35 @@
     /**
      * Creates a new builder instance using the given feature type as a template.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code template} argument type will be changed to {@code FeatureType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param template  an existing feature type to use as a template, or {@code null} if none.
      */
-    public FeatureTypeBuilder(final FeatureType template) {
+    public FeatureTypeBuilder(final DefaultFeatureType template) {
         this(template, null, null);
     }
 
     /**
      * Creates a new builder instance using the given name factory, template and locale for formatting error messages.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code template} argument type will be changed to {@code FeatureType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param template  an existing feature type to use as a template, or {@code null} if none.
      * @param factory   the factory to use for creating names, or {@code null} for the default factory.
      * @param locale    the locale to use for formatting error messages, or {@code null} for the default locale.
      */
-    public FeatureTypeBuilder(final FeatureType template, NameFactory factory, final Locale locale) {
+    public FeatureTypeBuilder(final DefaultFeatureType template, NameFactory factory, final Locale locale) {
         super(template, locale);
         if (factory == null) {
             factory = DefaultFactories.forBuildin(NameFactory.class);
         }
         nameFactory = factory;
         properties  = new ArrayList<PropertyTypeBuilder>();
-        superTypes  = new ArrayList<FeatureType>();
+        superTypes  = new ArrayList<DefaultFeatureType>();
         idDelimiter = ":";
         defaultMinimumOccurs = 1;
         defaultMaximumOccurs = 1;
@@ -179,12 +186,12 @@
             feature    = template;
             isAbstract = template.isAbstract();
             superTypes.addAll(template.getSuperTypes());
-            for (final PropertyType p : template.getProperties(false)) {
+            for (final AbstractIdentifiedType p : template.getProperties(false)) {
                 final PropertyTypeBuilder builder;
-                if (p instanceof AttributeType<?>) {
-                    builder = new AttributeTypeBuilder(this, (AttributeType<?>) p);
-                } else if (p instanceof FeatureAssociationRole) {
-                    builder = new AssociationRoleBuilder(this, (FeatureAssociationRole) p);
+                if (p instanceof DefaultAttributeType<?>) {
+                    builder = new AttributeTypeBuilder(this, (DefaultAttributeType<?>) p);
+                } else if (p instanceof DefaultAssociationRole) {
+                    builder = new AssociationRoleBuilder(this, (DefaultAssociationRole) p);
                 } else {
                     continue;           // Skip unknown types.
                 }
@@ -232,24 +239,32 @@
     /**
      * Returns the direct parents of the feature type to create.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The return type will be changed to {@code FeatureType[]} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @return the parents of the feature type to create, or an empty array if none.
      *
      * @see DefaultFeatureType#getSuperTypes()
      */
-    public FeatureType[] getSuperTypes() {
-        return superTypes.toArray(new FeatureType[superTypes.size()]);
+    public DefaultFeatureType[] getSuperTypes() {
+        return superTypes.toArray(new DefaultFeatureType[superTypes.size()]);
     }
 
     /**
      * Sets the parent types (or super-type) from which to inherit properties.
      * If this method is not invoked, then the default value is to have no parent.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code parents} argument type will be changed to {@code FeatureType...} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  parents  the parent types from which to inherit properties, or an empty array if none.
      * @return {@code this} for allowing method calls chaining.
      */
-    public FeatureTypeBuilder setSuperTypes(final FeatureType... parents) {
+    public FeatureTypeBuilder setSuperTypes(final DefaultFeatureType... parents) {
         ensureNonNull("parents", parents);
-        final List<FeatureType> asList = Arrays.asList(parents);
+        final List<DefaultFeatureType> asList = Arrays.asList(parents);
         if (!superTypes.equals(asList)) {
             superTypes.clear();
             superTypes.addAll(asList);
@@ -445,7 +460,7 @@
      */
     public <V> AttributeTypeBuilder<V> addAttribute(final Class<V> valueClass) {
         ensureNonNull("valueClass", valueClass);
-        if (Feature.class.isAssignableFrom(valueClass)) {
+        if (AbstractFeature.class.isAssignableFrom(valueClass)) {
             // We disallow Feature.class because that type shall be handled as association instead than attribute.
             throw new IllegalArgumentException(errors().getString(Errors.Keys.IllegalArgumentValue_2, "valueClass", valueClass));
         }
@@ -458,13 +473,17 @@
     /**
      * Creates a new {@code AttributeType} builder initialized to the same characteristics than the given template.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code template} argument type will be changed to {@code AttributeType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  <V>       the compile-time type of values in the {@code template} argument.
      * @param  template  an existing attribute type to use as a template.
      * @return a builder for an {@code AttributeType}, initialized with the values of the given template.
      *
      * @see #properties()
      */
-    public <V> AttributeTypeBuilder<V> addAttribute(final AttributeType<V> template) {
+    public <V> AttributeTypeBuilder<V> addAttribute(final DefaultAttributeType<V> template) {
         ensureNonNull("template", template);
         final AttributeTypeBuilder<V> property = new AttributeTypeBuilder<V>(this, template);
         properties.add(property);
@@ -477,12 +496,16 @@
      * The default association name is the name of the given type, but callers should invoke one
      * of the {@code AssociationRoleBuilder.setName(…)} methods on the returned instance with a better name.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code type} argument type will be changed to {@code FeatureType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  type  the type of feature values.
      * @return a builder for a {@code FeatureAssociationRole}.
      *
      * @see #properties()
      */
-    public AssociationRoleBuilder addAssociation(final FeatureType type) {
+    public AssociationRoleBuilder addAssociation(final DefaultFeatureType type) {
         ensureNonNull("type", type);
         final AssociationRoleBuilder property = new AssociationRoleBuilder(this, type, type.getName());
         properties.add(property);
@@ -512,12 +535,16 @@
      * Creates a new {@code FeatureAssociationRole} builder initialized to the same characteristics
      * than the given template.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The {@code template} argument type will be changed to {@code FeatureAssociationRole} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @param  template  an existing feature association to use as a template.
      * @return a builder for an {@code FeatureAssociationRole}, initialized with the values of the given template.
      *
      * @see #properties()
      */
-    public AssociationRoleBuilder addAssociation(final FeatureAssociationRole template) {
+    public AssociationRoleBuilder addAssociation(final DefaultAssociationRole template) {
         ensureNonNull("template", template);
         final AssociationRoleBuilder property = new AssociationRoleBuilder(this, template);
         properties.add(property);
@@ -557,11 +584,15 @@
      * One of the {@code setName(…)} methods must have been invoked before this {@code build()} method (mandatory).
      * All other methods are optional, but some calls to a {@code add} method are usually needed.
      *
+     * <div class="warning"><b>Warning:</b>
+     * The return type will be changed to {@code FeatureType} if and when such interface
+     * will be defined in GeoAPI.</div>
+     *
      * @return the new feature type.
      * @throws IllegalStateException if the feature type contains incompatible
      *         {@linkplain AttributeTypeBuilder#setCRS CRS characteristics}.
      */
-    public FeatureType build() throws IllegalStateException {
+    public DefaultFeatureType build() throws IllegalStateException {
         if (feature == null) {
             /*
              * Creates an initial array of property types with up to 3 slots reserved for @identifier, @geometry
@@ -572,25 +603,25 @@
             int numSynthetic;                               // Number of synthetic properties that may be generated.
             int envelopeIndex = -1;
             int geometryIndex = -1;
-            final PropertyType[] identifierTypes;
+            final AbstractIdentifiedType[] identifierTypes;
             if (identifierCount == 0) {
                 numSynthetic    = 0;
                 identifierTypes = null;
             } else {
                 numSynthetic    = 1;
-                identifierTypes = new PropertyType[identifierCount];
+                identifierTypes = new AbstractIdentifiedType[identifierCount];
             }
             if (defaultGeometry != null) {
                 envelopeIndex = numSynthetic;
                 geometryIndex = numSynthetic + 1;
                 numSynthetic += 2;
             }
-            final PropertyType[] propertyTypes = new PropertyType[numSynthetic + numSpecified];
+            final AbstractIdentifiedType[] propertyTypes = new AbstractIdentifiedType[numSynthetic + numSpecified];
             int propertyCursor = numSynthetic;
             int identifierCursor = 0;
             for (int i=0; i<numSpecified; i++) {
                 final PropertyTypeBuilder builder = properties.get(i);
-                final PropertyType instance = builder.build();
+                final AbstractIdentifiedType instance = builder.build();
                 propertyTypes[propertyCursor] = instance;
                 /*
                  * Collect the attributes to use as identifier components while we loop over all properties.
@@ -650,7 +681,7 @@
                 }
             }
             feature = new DefaultFeatureType(identification(), isAbstract(),
-                    superTypes.toArray(new FeatureType[superTypes.size()]),
+                    superTypes.toArray(new DefaultFeatureType[superTypes.size()]),
                     ArraysExt.resize(propertyTypes, propertyCursor));
         }
         return feature;
@@ -672,7 +703,7 @@
             buffer.insert(buffer.indexOf("[") + 1, "abstract ");
         }
         String separator = " : ";
-        for (final FeatureType parent : superTypes) {
+        for (final DefaultFeatureType parent : superTypes) {
             buffer.append(separator).append('“').append(parent.getName()).append('”');
             separator = ", ";
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java
index acd4eb4..42bdfc6 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/PropertyTypeBuilder.java
@@ -20,10 +20,7 @@
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.FeatureAssociationRole;
+import org.apache.sis.feature.AbstractIdentifiedType;
 
 
 /**
@@ -71,7 +68,7 @@
      * The attribute or association created by this builder, or {@code null} if not yet created.
      * This field must be cleared every time that a setter method is invoked on this builder.
      */
-    private transient PropertyType property;
+    private transient AbstractIdentifiedType property;
 
     /**
      * Creates a new {@code PropertyType} builder initialized to the values of an existing property.
@@ -79,7 +76,7 @@
      * @param owner     the builder of the {@code FeatureType} for which to add this property.
      * @param template  an existing property to use as a template, or {@code null} if none.
      */
-    PropertyTypeBuilder(final FeatureTypeBuilder owner, final PropertyType template) {
+    PropertyTypeBuilder(final FeatureTypeBuilder owner, final AbstractIdentifiedType template) {
         super(template, owner.getLocale());
         this.owner    = owner;
         minimumOccurs = owner.defaultMinimumOccurs;
@@ -140,7 +137,7 @@
      * Returns the property type from the current setting.
      * This method may return an existing property if it was already created.
      */
-    final PropertyType build() {
+    final AbstractIdentifiedType build() {
         if (property == null) {
             property = create();
         }
@@ -150,5 +147,5 @@
     /**
      * Creates a new property type from the current setting.
      */
-    abstract PropertyType create();
+    abstract AbstractIdentifiedType create();
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java
index 1cab04e..dc1aeb8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/builder/TypeBuilder.java
@@ -30,7 +30,6 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.IdentifiedType;
 
 
 /**
@@ -66,7 +65,7 @@
     /**
      * Creates a new builder initialized to the values of an existing type.
      */
-    TypeBuilder(final IdentifiedType template, final Locale locale) {
+    TypeBuilder(final AbstractIdentifiedType template, final Locale locale) {
         putIfNonNull(Errors.LOCALE_KEY, locale);
         if (template != null) {
             putIfNonNull(AbstractIdentifiedType.NAME_KEY,        template.getName());
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
index 6a79c4e..ce210d6 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
@@ -27,11 +27,10 @@
 import org.apache.sis.util.Static;
 
 // Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
+import org.apache.sis.feature.AbstractAttribute;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.AbstractOperation;
+import org.apache.sis.feature.DefaultAttributeType;
 
 
 /**
@@ -225,11 +224,11 @@
      *
      * @see #GEOMETRY_PROPERTY
      */
-    public static boolean isGeometryAttribute(IdentifiedType type) {
-        while (type instanceof Operation) {
-            type = ((Operation) type).getResult();
+    public static boolean isGeometryAttribute(AbstractIdentifiedType type) {
+        while (type instanceof AbstractOperation) {
+            type = ((AbstractOperation) type).getResult();
         }
-        return (type instanceof AttributeType<?>) && Geometries.isKnownType(((AttributeType<?>) type).getValueClass());
+        return (type instanceof DefaultAttributeType<?>) && Geometries.isKnownType(((DefaultAttributeType<?>) type).getValueClass());
     }
 
     /**
@@ -240,7 +239,7 @@
      * @param  type  the operation or attribute type for which to get the CRS, or {@code null}.
      * @return {@code true} if a characteristic for Coordinate Reference System has been found.
      */
-    public static boolean characterizedByCRS(final IdentifiedType type) {
+    public static boolean characterizedByCRS(final AbstractIdentifiedType type) {
         return hasCharacteristic(type, CRS_CHARACTERISTIC.toString(), CoordinateReferenceSystem.class);
     }
 
@@ -255,7 +254,7 @@
      *
      * @see org.apache.sis.feature.builder.AttributeTypeBuilder#setCRS(CoordinateReferenceSystem)
      */
-    public static CoordinateReferenceSystem getCRSCharacteristic(final Property attribute) {
+    public static CoordinateReferenceSystem getCRSCharacteristic(final Object attribute) {
         return (CoordinateReferenceSystem) getCharacteristic(attribute, CRS_CHARACTERISTIC.toString());
     }
 
@@ -267,7 +266,7 @@
      * @param  type  the operation or attribute type for which to get the maximal length, or {@code null}.
      * @return {@code true} if a characteristic for maximal length has been found.
      */
-    public static boolean characterizedByMaximalLength(final IdentifiedType type) {
+    public static boolean characterizedByMaximalLength(final AbstractIdentifiedType type) {
         return hasCharacteristic(type, MAXIMAL_LENGTH_CHARACTERISTIC.toString(), Integer.class);
     }
 
@@ -282,7 +281,7 @@
      *
      * @see org.apache.sis.feature.builder.AttributeTypeBuilder#setMaximalLength(Integer)
      */
-    public static Integer getMaximalLengthCharacteristic(final Property attribute) {
+    public static Integer getMaximalLengthCharacteristic(final Object attribute) {
         return (Integer) getCharacteristic(attribute, MAXIMAL_LENGTH_CHARACTERISTIC.toString());
     }
 
@@ -295,12 +294,12 @@
      * @param  valueClass  the expected characteristic values.
      * @return {@code true} if a characteristic of the given name exists and has values assignable to the given class.
      */
-    private static boolean hasCharacteristic(IdentifiedType type, final String name, final Class<?> valueClass) {
-        while (type instanceof Operation) {
-            type = ((Operation) type).getResult();
+    private static boolean hasCharacteristic(AbstractIdentifiedType type, final String name, final Class<?> valueClass) {
+        while (type instanceof AbstractOperation) {
+            type = ((AbstractOperation) type).getResult();
         }
-        if (type instanceof AttributeType<?>) {
-            final AttributeType<?> at = ((AttributeType<?>) type).characteristics().get(name);
+        if (type instanceof DefaultAttributeType<?>) {
+            final DefaultAttributeType<?> at = ((DefaultAttributeType<?>) type).characteristics().get(name);
             if (at != null) {
                 return valueClass.isAssignableFrom(at.getValueClass());
             }
@@ -317,16 +316,16 @@
      * @param  name       name of the characteristic to get.
      * @return the value or default value of the given characteristic in the given property, or {@code null} if none.
      */
-    private static Object getCharacteristic(final Property attribute, final String name) {
-        if (attribute instanceof Attribute<?>) {
-            final Attribute<?> at = ((Attribute<?>) attribute).characteristics().get(name);
+    private static Object getCharacteristic(final Object attribute, final String name) {
+        if (attribute instanceof AbstractAttribute<?>) {
+            final AbstractAttribute<?> at = ((AbstractAttribute<?>) attribute).characteristics().get(name);
             if (at != null) {
                 final Object value = at.getValue();
                 if (value != null) {
                     return value;
                 }
             }
-            final AttributeType<?> type = ((Attribute<?>) attribute).getType().characteristics().get(name);
+            final DefaultAttributeType<?> type = ((AbstractAttribute<?>) attribute).getType().characteristics().get(name);
             if (type != null) {
                 return type.getDefaultValue();
             }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java
index 74a94cd..e50dd8c 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicMapTest.java
@@ -26,9 +26,6 @@
 
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Attribute;
-
 
 /**
  * Tests {@link CharacteristicMap} indirectly, through {@link AbstractAttribute} construction.
@@ -66,10 +63,10 @@
      */
     @Test
     public void testPut() {
-        final AbstractAttribute<?>     temperature     = temperature();
-        final AbstractAttribute<?>     units           = create(temperature, "units");
-        final AbstractAttribute<?>     accuracy        = create(temperature, "accuracy");
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
+        final AbstractAttribute<?> temperature = temperature();
+        final AbstractAttribute<?> units       = create(temperature, "units");
+        final AbstractAttribute<?> accuracy    = create(temperature, "accuracy");
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
         /*
          * Verify that the map is initially empty.
          */
@@ -154,11 +151,11 @@
     @Test
     @DependsOnMethod("testPut")
     public void testAddValue() {
-        final AbstractAttribute<?>     temperature     = temperature();
-        final AbstractAttribute<?>     units           = create(temperature, "units");
-        final AbstractAttribute<?>     accuracy        = create(temperature, "accuracy");
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
-        final Collection<Attribute<?>> values          = characteristics.values();
+        final AbstractAttribute<?> temperature = temperature();
+        final AbstractAttribute<?> units       = create(temperature, "units");
+        final AbstractAttribute<?> accuracy    = create(temperature, "accuracy");
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
+        final Collection<AbstractAttribute<?>> values          = characteristics.values();
         /*
          * Verify that the collection is initially empty.
          */
@@ -212,10 +209,10 @@
     @Test
     @DependsOnMethod("testPut")
     public void testAddKey() {
-        final Attribute<?> units, accuracy;
-        final AbstractAttribute<?>     temperature     = temperature();
-        final Map<String,Attribute<?>> characteristics = temperature.characteristics();
-        final Collection<String>       keys            = characteristics.keySet();
+        final AbstractAttribute<?> units, accuracy;
+        final AbstractAttribute<?> temperature = temperature();
+        final Map<String,AbstractAttribute<?>> characteristics = temperature.characteristics();
+        final Collection<String> keys = characteristics.keySet();
         /*
          * Verify that the collection is initially empty.
          */
@@ -273,14 +270,14 @@
      * @param accuracy        The second expected value in iteration order.
      * @param characteristics The map to verify.
      */
-    private static void assertEntriesEqual(final Attribute<?> units, final Attribute<?> accuracy,
-            final Map<String,Attribute<?>> characteristics)
+    private static void assertEntriesEqual(final AbstractAttribute<?> units, final AbstractAttribute<?> accuracy,
+            final Map<String,AbstractAttribute<?>> characteristics)
     {
         assertArrayEquals("keySet", new String[] {"accuracy", "units"}, characteristics.keySet().toArray());
         assertArrayEquals("values", new Object[] { accuracy ,  units }, characteristics.values().toArray());
         assertArrayEquals("entrySet", new Object[] {
-                new SimpleEntry<String,Attribute<?>>("accuracy", accuracy),
-                new SimpleEntry<String,Attribute<?>>("units",    units)
+                new SimpleEntry<String,AbstractAttribute<?>>("accuracy", accuracy),
+                new SimpleEntry<String,AbstractAttribute<?>>("units",    units)
             }, characteristics.entrySet().toArray());
     }
 
@@ -293,7 +290,7 @@
      */
     private static void setAccuracy(final AbstractAttribute<Float> temperature, final boolean isFirstTime, final float value) {
         assertEquals("keySet.add", isFirstTime, temperature.characteristics().keySet().add("accuracy"));
-        final Attribute<Float> accuracy = Features.cast(temperature.characteristics().get("accuracy"), Float.class);
+        final AbstractAttribute<Float> accuracy = Features.cast(temperature.characteristics().get("accuracy"), Float.class);
         accuracy.setValue(value);
     }
 
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
index 659364a..13490b8 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/CharacteristicTypeMapTest.java
@@ -26,9 +26,6 @@
 import static org.apache.sis.feature.DefaultAssociationRole.NAME_KEY;
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-
 
 /**
  * Tests {@link CharacteristicTypeMap} indirectly, through {@link DefaultAttributeType} construction.
@@ -74,9 +71,9 @@
      */
     @Test
     public void testMapMethods() {
-        final AttributeType<?> units, accuracy;
+        final DefaultAttributeType<?> units, accuracy;
         final DefaultAttributeType<Float> temperature = temperature();
-        final Map<String, AttributeType<?>> characteristics = temperature.characteristics();
+        final Map<String, DefaultAttributeType<?>> characteristics = temperature.characteristics();
 
         assertFalse  ("isEmpty",        characteristics.isEmpty());
         assertEquals ("size", 2,        characteristics.size());
@@ -94,8 +91,8 @@
         assertArrayEquals("keySet", new String[] {"accuracy", "units"}, characteristics.keySet().toArray());
         assertArrayEquals("values", new Object[] { accuracy ,  units }, characteristics.values().toArray());
         assertArrayEquals("entrySet", new Object[] {
-                new SimpleEntry<String,AttributeType<?>>("accuracy", accuracy),
-                new SimpleEntry<String,AttributeType<?>>("units",    units)
+                new SimpleEntry<String,DefaultAttributeType<?>>("accuracy", accuracy),
+                new SimpleEntry<String,DefaultAttributeType<?>>("units",    units)
             }, characteristics.entrySet().toArray());
     }
 
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java b/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java
index 9e1546d..743295a 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/CustomAttribute.java
@@ -25,9 +25,6 @@
 
 import static java.util.Collections.singleton;
 
-// Branch-dependent imports
-import org.opengis.feature.AttributeType;
-
 
 /**
  * For testing {@link AbstractAttribute} customization.
@@ -53,7 +50,7 @@
     /**
      * Creates a new attribute.
      */
-    public CustomAttribute(final AttributeType<V> type) {
+    public CustomAttribute(final DefaultAttributeType<V> type) {
         super(type);
         value = type.getDefaultValue();
     }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
index fab8bfc..6177890 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultAssociationRoleTest.java
@@ -19,7 +19,6 @@
 import java.util.Map;
 import org.opengis.util.GenericName;
 import org.opengis.util.NameFactory;
-import org.opengis.feature.FeatureAssociationRole;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -31,9 +30,6 @@
 import static org.apache.sis.test.TestUtilities.getSingleton;
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.FeatureType;
-
 
 /**
  * Tests {@link DefaultAssociationRole}.
@@ -74,7 +70,7 @@
      */
     static DefaultFeatureType twinTownCity(final boolean cyclic) {
         final DefaultAssociationRole twinTown = twinTown(cyclic);
-        final FeatureType parent = cyclic ? DefaultFeatureTypeTest.city() : twinTown.getValueType();
+        final DefaultFeatureType parent = cyclic ? DefaultFeatureTypeTest.city() : twinTown.getValueType();
         return createType("Twin town", parent, twinTown);
     }
 
@@ -87,10 +83,10 @@
      * @return The feature type to use for testing purpose.
      */
     private static DefaultFeatureType createType(final Object name,
-            final FeatureType parent, final FeatureAssociationRole... property)
+            final DefaultFeatureType parent, final DefaultAssociationRole... property)
     {
         return new DefaultFeatureType(singletonMap(NAME_KEY, name),
-                false, new FeatureType[] {parent}, property);
+                false, new DefaultFeatureType[] {parent}, property);
     }
 
     /**
@@ -126,7 +122,7 @@
     @Test
     public void testBidirectionalAssociation() {
         final DefaultFeatureType twinTown = twinTownCity(true);
-        final FeatureAssociationRole association = (FeatureAssociationRole) twinTown.getProperty("twin town");
+        final DefaultAssociationRole association = (DefaultAssociationRole) twinTown.getProperty("twin town");
         assertSame("twinTown.property(“twin town”).valueType", twinTown, association.getValueType());
         /*
          * Creates a FeatureType copy containing the same properties. Used for verifying
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
index 48b1070..17d6c08 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
@@ -32,9 +32,6 @@
 import static java.util.Collections.singletonMap;
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-
 
 /**
  * Tests {@link DefaultFeatureType}.
@@ -201,7 +198,7 @@
             final String... expected)
     {
         int index = 0;
-        for (final PropertyType property : feature.getProperties(includeSuperTypes)) {
+        for (final AbstractIdentifiedType property : feature.getProperties(includeSuperTypes)) {
             assertTrue("Found more properties than expected.", index < expected.length);
             final String name = expected[index++];
             assertNotNull(name, property);
@@ -274,8 +271,8 @@
                 false, null, city, population, festival);
 
         assertUnmodifiable(complex);
-        final Collection<PropertyType> properties = complex.getProperties(false);
-        final Iterator<PropertyType> it = properties.iterator();
+        final Collection<AbstractIdentifiedType> properties = complex.getProperties(false);
+        final Iterator<AbstractIdentifiedType> it = properties.iterator();
 
         assertEquals("name",            "Festival",                     complex.getName().toString());
         assertTrue  ("superTypes",                                      complex.getSuperTypes().isEmpty());
@@ -340,7 +337,7 @@
                 singletonMap(DefaultAttributeType.NAME_KEY, "City"),
                 false, null, city, cityId, population);
 
-        final Iterator<PropertyType> it = feature.getProperties(false).iterator();
+        final Iterator<AbstractIdentifiedType> it = feature.getProperties(false).iterator();
         assertSame ("properties[0]", city,       it.next());
         assertSame ("properties[1]", cityId,     it.next());
         assertSame ("properties[2]", population, it.next());
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
index 51ed9dc..3c9b4ff 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
@@ -36,9 +36,6 @@
 
 import static org.apache.sis.test.ReferencingAssert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-
 
 /**
  * Tests {@link EnvelopeOperation}.
@@ -73,7 +70,7 @@
         final DefaultAttributeType<?> normalizedCRS = new DefaultAttributeType<CoordinateReferenceSystem>(
                 name(AttributeConvention.CRS_CHARACTERISTIC), CoordinateReferenceSystem.class, 1, 1, HardCodedCRS.WGS84);
 
-        final PropertyType[] attributes = {
+        final AbstractIdentifiedType[] attributes = {
             new DefaultAttributeType<String> (name("name"),          String.class,  1, 1, null),
             new DefaultAttributeType<Polygon>(name("classes"),       Polygon.class, 1, 1, null, standardCRS),
             new DefaultAttributeType<Point>  (name("climbing wall"), Point.class,   1, 1, null, standardCRS),
@@ -103,7 +100,7 @@
      */
     @Test
     public void testConstruction() throws FactoryException {
-        final PropertyType property = school(3).getProperty("bounds");
+        final AbstractIdentifiedType property = school(3).getProperty("bounds");
         assertInstanceOf("bounds", EnvelopeOperation.class, property);
         final EnvelopeOperation op = (EnvelopeOperation) property;
         assertSame("crs", HardCodedCRS.WGS84, op.crs);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java
index 8b33fd5..0afa3c1 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureMemoryBenchmark.java
@@ -20,7 +20,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Random;
-import org.opengis.feature.Feature;
 
 import static java.util.Collections.singletonMap;
 
@@ -125,7 +124,7 @@
         final Float  latitude  = random.nextFloat() * 180 -  90;
         final Float  longitude = random.nextFloat() * 360 - 180;
         if (type != null) {
-            final Feature feature = type.newInstance();
+            final AbstractFeature feature = type.newInstance();
             feature.setPropertyValue("city",      city);
             feature.setPropertyValue("latitude",  latitude);
             feature.setPropertyValue("longitude", longitude);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
index dbca8d2..e59fa5b 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
@@ -135,9 +135,9 @@
         feature.setPropertyValue("REF_INSEE",   "92007");
         feature.setPropertyValue("CODE_POSTAL", "92220");
 
-        assertEquals("CODE_POSTAL", "92220",   feature.getProperty("CODE_POSTAL").getValue());
-        assertEquals("REF_INSEE",   "92007",   feature.getProperty("REF_INSEE")  .getValue());
-        assertEquals("COMMUNE",     "Bagneux", feature.getProperty("COMMUNE")    .getValue());
+        assertEquals("CODE_POSTAL", "92220",   ((AbstractAttribute) feature.getProperty("CODE_POSTAL")).getValue());
+        assertEquals("REF_INSEE",   "92007",   ((AbstractAttribute) feature.getProperty("REF_INSEE"))  .getValue());
+        assertEquals("COMMUNE",     "Bagneux", ((AbstractAttribute) feature.getProperty("COMMUNE"))    .getValue());
 
         assertEquals("CODE_POSTAL", "92220",   feature.getPropertyValue("CODE_POSTAL"));
         assertEquals("REF_INSEE",   "92007",   feature.getPropertyValue("REF_INSEE"));
@@ -370,13 +370,13 @@
          * Force the conversion of a property value into a full Property object on one and only one of
          * the Features to be compared. The implementation shall be able to wrap or unwrap the values.
          */
-        assertEquals("Tokyo", clone.getProperty("city").getValue());
+        assertEquals("Tokyo", ((AbstractAttribute) clone.getProperty("city")).getValue());
         assertEquals("hashCode", feature.hashCode(), clone.hashCode());
         assertEquals("equals", feature, clone);
         /*
          * For the other Feature instance to contain full Property object and test again.
          */
-        assertEquals("Tokyo", feature.getProperty("city").getValue());
+        assertEquals("Tokyo", ((AbstractAttribute) feature.getProperty("city")).getValue());
         assertEquals("hashCode", feature.hashCode(), clone.hashCode());
         assertEquals("equals", feature, clone);
     }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
index 737c8dc..6a9c1cb 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
@@ -22,10 +22,6 @@
 
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Tests {@link Features}.
@@ -79,13 +75,13 @@
      */
     @Test
     public void testValidate() {
-        final Feature feature = DefaultFeatureTypeTest.city().newInstance();
+        final AbstractFeature feature = DefaultFeatureTypeTest.city().newInstance();
 
         // Should not pass validation.
         try {
             Features.validate(feature);
             fail("Feature is invalid because of missing property “population”. Validation should have raised an exception.");
-        } catch (InvalidPropertyValueException ex) {
+        } catch (IllegalArgumentException ex) {
             String message = ex.getMessage();
             assertTrue(message, message.contains("city") || message.contains("population"));
         }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java b/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java
index 91b3ef5..b3c7b82 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java
@@ -20,11 +20,6 @@
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Property;
-
 
 /**
  * An operation that does nothing.
@@ -45,7 +40,7 @@
     /**
      * The type of the result, or {@code null} if none.
      */
-    private final IdentifiedType result;
+    private final AbstractIdentifiedType result;
 
     /**
      * Constructs an operation from the given properties. The identification map is given unchanged to
@@ -56,7 +51,7 @@
      * @param result         The type of the result, or {@code null} if none.
      */
     NoOperation(final Map<String,?> identification,
-            final ParameterDescriptorGroup parameters, final IdentifiedType result)
+            final ParameterDescriptorGroup parameters, final AbstractIdentifiedType result)
     {
         super(identification);
         this.parameters = parameters;
@@ -79,7 +74,7 @@
      * @return The type of the result, or {@code null} if none.
      */
     @Override
-    public IdentifiedType getResult() {
+    public AbstractIdentifiedType getResult() {
         return result;
     }
 
@@ -89,7 +84,7 @@
      * @return {@code null}
      */
     @Override
-    public Property apply(Feature feature, ParameterValueGroup parameters) {
+    public Object apply(AbstractFeature feature, ParameterValueGroup parameters) {
         return null;
     }
 }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
index ca3778c..d7af014 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAssociationTest.java
@@ -23,10 +23,6 @@
 import static java.util.Collections.singletonMap;
 import static org.apache.sis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.PropertyType;
-
 
 /**
  * Tests {@link SingletonAssociation}.
@@ -48,7 +44,7 @@
      * and Le Mans, France in 836.” — source: Wikipedia</blockquote>
      */
     static AbstractAssociation twinTown() {
-        final Feature twinTown = DefaultFeatureTypeTest.city().newInstance();
+        final AbstractFeature twinTown = DefaultFeatureTypeTest.city().newInstance();
         twinTown.setPropertyValue("city", "Le Mans");
         twinTown.setPropertyValue("population", 143240); // In 2011.
         final AbstractAssociation association = new SingletonAssociation(DefaultAssociationRoleTest.twinTown(false));
@@ -61,9 +57,9 @@
      */
     @Test
     public void testWrongValue() {
-        final AbstractAssociation association  = twinTown();
-        final PropertyType population   = association.getRole().getValueType().getProperty("population");
-        final Feature      otherFeature = new DefaultFeatureType(
+        final AbstractAssociation    association  = twinTown();
+        final AbstractIdentifiedType population   = association.getRole().getValueType().getProperty("population");
+        final AbstractFeature        otherFeature = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Population"), false, null, population).newInstance();
         try {
             association.setValue(otherFeature);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
index 58565ce..adc5813 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
@@ -25,10 +25,6 @@
 
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Tests {@link StringJoinOperation}.
@@ -58,9 +54,9 @@
      * @return The feature for a person.
      */
     private static DefaultFeatureType person() {
-        final PropertyType nameType = new DefaultAttributeType<String> (name("name"), String.class, 1, 1, null);
-        final PropertyType ageType  = new DefaultAttributeType<Integer>(name("age"), Integer.class, 1, 1, null);
-        final PropertyType cmpType  = FeatureOperations.compound(name("concat"), "/", "<<:", ":>>", nameType, ageType);
+        final AbstractIdentifiedType nameType = new DefaultAttributeType<String> (name("name"), String.class, 1, 1, null);
+        final AbstractIdentifiedType ageType  = new DefaultAttributeType<Integer>(name("age"), Integer.class, 1, 1, null);
+        final AbstractIdentifiedType cmpType  = FeatureOperations.compound(name("concat"), "/", "<<:", ":>>", nameType, ageType);
         return new DefaultFeatureType(name("person"), false, null, nameType, ageType, cmpType);
     }
 
@@ -143,7 +139,7 @@
         try {
             feature.setPropertyValue("concat", "((:marc/21:>>");
             fail("Should fail because of mismatched prefix.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("<<:"));
             assertTrue(message, message.contains("(("));
@@ -151,7 +147,7 @@
         try {
             feature.setPropertyValue("concat", "<<:marc/21:))");
             fail("Should fail because of mismatched suffix.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains(":>>"));
             assertTrue(message, message.contains("))"));
@@ -159,14 +155,14 @@
         try {
             feature.setPropertyValue("concat", "<<:marc/21/julie:>>");
             fail("Should fail because of too many components.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("<<:marc/21/julie:>>"));
         }
         try {
             feature.setPropertyValue("concat", "<<:marc/julie:>>");
             fail("Should fail because of unparsable number.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("julie"));
             assertTrue(message, message.contains("age"));
diff --git a/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java b/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java
index 16e1d5a..6874c8b 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/feature/builder/FeatureTypeBuilderTest.java
@@ -30,9 +30,9 @@
 import static org.junit.Assert.*;
 
 // Branch-dependent imports
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.DefaultAttributeType;
+import org.apache.sis.feature.DefaultFeatureType;
 
 
 /**
@@ -54,7 +54,7 @@
         assertEquals("default name", "string", builder.getName().toString());
 
         builder.setName("myScope", "myName");
-        final AttributeType<?> att = (AttributeType<?>) builder.build();
+        final DefaultAttributeType<?> att = (DefaultAttributeType<?>) builder.build();
 
         assertEquals("name", "myScope:myName",   att.getName().toString());
         assertEquals("valueClass", String.class, att.getValueClass());
@@ -88,7 +88,7 @@
      */
     private static void testEmptyFeature(final FeatureTypeBuilder builder) {
         builder.setName("scope", "test");
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
 
         assertEquals("name", "scope:test",   type.getName().toString());
         assertFalse ("isAbstract",           type.isAbstract());
@@ -110,7 +110,7 @@
         builder.setDefaultValue("test default value.");
         builder.setCardinality(10, 60);
         builder.setMaximalLength(80);
-        final AttributeType<?> att = (AttributeType<?>) builder.build();
+        final DefaultAttributeType<?> att = (DefaultAttributeType<?>) builder.build();
 
         assertEquals("name",          "myScope:myName",      att.getName().toString());
         assertEquals("definition",    "test definition",     att.getDefinition().toString());
@@ -148,18 +148,18 @@
         builder.addAttribute(Point  .class).setName("location").setCRS(HardCodedCRS.WGS84);
         builder.addAttribute(Double .class).setName("score").setDefaultValue(10.0).setCardinality(5, 50);
 
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
         assertEquals("name",        "myScope:myName",   type.getName().toString());
         assertEquals("definition",  "test definition",  type.getDefinition().toString());
         assertEquals("description", "test description", type.getDescription().toString());
         assertEquals("designation", "test designation", type.getDesignation().toString());
         assertTrue  ("isAbstract",                      type.isAbstract());
 
-        final Iterator<? extends PropertyType> it = type.getProperties(true).iterator();
-        final AttributeType<?> a0 = (AttributeType<?>) it.next();
-        final AttributeType<?> a1 = (AttributeType<?>) it.next();
-        final AttributeType<?> a2 = (AttributeType<?>) it.next();
-        final AttributeType<?> a3 = (AttributeType<?>) it.next();
+        final Iterator<? extends AbstractIdentifiedType> it = type.getProperties(true).iterator();
+        final DefaultAttributeType<?> a0 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a1 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a2 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a3 = (DefaultAttributeType<?>) it.next();
         assertFalse("properties count", it.hasNext());
 
         assertEquals("name", "name",     a0.getName().toString());
@@ -208,16 +208,16 @@
                 .setCRS(HardCodedCRS.WGS84)
                 .addRole(AttributeRole.DEFAULT_GEOMETRY);
 
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
         assertEquals("name", "scope:test", type.getName().toString());
         assertFalse ("isAbstract", type.isAbstract());
 
-        final Iterator<? extends PropertyType> it = type.getProperties(true).iterator();
-        final PropertyType a0 = it.next();
-        final PropertyType a1 = it.next();
-        final PropertyType a2 = it.next();
-        final PropertyType a3 = it.next();
-        final PropertyType a4 = it.next();
+        final Iterator<? extends AbstractIdentifiedType> it = type.getProperties(true).iterator();
+        final AbstractIdentifiedType a0 = it.next();
+        final AbstractIdentifiedType a1 = it.next();
+        final AbstractIdentifiedType a2 = it.next();
+        final AbstractIdentifiedType a3 = it.next();
+        final AbstractIdentifiedType a4 = it.next();
         assertFalse("properties count", it.hasNext());
 
         assertEquals("name", AttributeConvention.IDENTIFIER_PROPERTY, a0.getName());
diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
index 31296af..37f3b1a 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
@@ -28,10 +28,6 @@
 
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.IdentifiedType;
-
 
 /**
  * Tests {@link AttributeConvention}.
diff --git a/core/sis-metadata/pom.xml b/core/sis-metadata/pom.xml
index af891e0..d003cc3 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/DCPList.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/DCPList.java
index d019675..15d9838 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/DCPList.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/DCPList.java
@@ -17,10 +17,9 @@
 package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.metadata.identification.DistributedComputingPlatform;
-import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
-import org.apache.sis.internal.jaxb.gmd.CodeListUID;
 import org.apache.sis.xml.Namespaces;
+import org.apache.sis.internal.jaxb.gmd.CodeListUID;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeListAdapter;
 
 
 /**
@@ -33,7 +32,7 @@
  * @version 0.5
  * @module
  */
-public final class DCPList extends CodeListAdapter<DCPList, DistributedComputingPlatform> {
+public final class DCPList extends UnsupportedCodeListAdapter<DCPList> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -60,11 +59,32 @@
     /**
      * {@inheritDoc}
      *
-     * @return The code list class.
+     * @return The code list class name.
      */
     @Override
-    protected Class<DistributedComputingPlatform> getCodeListClass() {
-        return DistributedComputingPlatform.class;
+    protected String getCodeListName() {
+        return "DCPList";
+    }
+
+    /**
+     * Converts the given Java constant name to something hopefully close to the UML identifier,
+     * or close to the textual value to put in the XML.
+     *
+     * @param  name    The Java constant name (e.g. {@code WEB_SERVICES}).
+     * @param  buffer  An initially empty buffer to use for creating the identifier.
+     * @param  isValue {@code false} for the {@code codeListValue} attribute, or {@code true} for the XML value.
+     * @return The identifier (e.g. {@code "WebServices"} or {@code "Web services"}).
+     */
+    @Override
+    protected String toIdentifier(final String name, final StringBuilder buffer, final boolean isValue) {
+        if (name.startsWith("WEB_")) {
+            super.toIdentifier(name, buffer, isValue);
+            buffer.setCharAt(0, 'W');
+            return buffer.toString();
+        } else {
+            // Other names are abbreviations (e.g. XML, SQL, FTP, etc.), so return unchanged.
+            return name;
+        }
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java
deleted file mode 100644
index 1079803..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java
+++ /dev/null
@@ -1,89 +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.jaxb.code;
-
-import javax.xml.bind.annotation.XmlElement;
-import org.opengis.metadata.identification.CharacterSet;
-import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
-import org.apache.sis.internal.jaxb.gmd.CodeListUID;
-
-
-/**
- * JAXB adapter for {@link CharacterSet}, in order to integrate the value in an element
- * complying with ISO-19139 standard. See package documentation for more information about
- * the handling of {@code CodeList} in ISO-19139.
- *
- * @author  Cédric Briançon (Geomatys)
- * @since   0.3
- * @version 0.5
- * @module
- */
-@SuppressWarnings("deprecation")
-public final class LegacyCharacterSet extends CodeListAdapter<LegacyCharacterSet, CharacterSet> {
-    /**
-     * Empty constructor for JAXB only.
-     */
-    public LegacyCharacterSet() {
-    }
-
-    /**
-     * Creates a new adapter for the given value.
-     */
-    private LegacyCharacterSet(final CodeListUID value) {
-        super(value);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @return The wrapper for the code list value.
-     */
-    @Override
-    protected LegacyCharacterSet wrap(final CodeListUID value) {
-        return new LegacyCharacterSet(value);
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * @return The code list class.
-     */
-    @Override
-    protected Class<CharacterSet> getCodeListClass() {
-        return CharacterSet.class;
-    }
-
-    /**
-     * Invoked by JAXB on marshalling.
-     *
-     * @return The value to be marshalled.
-     */
-    @Override
-    @XmlElement(name = "MD_CharacterSetCode")
-    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_CharacterSetCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetCode.java
index 6a23d1e..f236384 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetCode.java
@@ -16,67 +16,50 @@
  */
 package org.apache.sis.internal.jaxb.code;
 
-import java.util.Locale;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.apache.sis.xml.ValueConverter;
-import org.apache.sis.internal.jaxb.Context;
+import org.opengis.metadata.identification.CharacterSet;
+import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
 import org.apache.sis.internal.jaxb.gmd.CodeListUID;
 
 
 /**
- * JAXB adapter for {@link Charset}, in order to integrate the value in an element
+ * JAXB adapter for {@link CharacterSet}, in order to integrate the value in an element
  * complying with ISO-19139 standard. See package documentation for more information about
  * the handling of {@code CodeList} in ISO-19139.
  *
  * @author  Cédric Briançon (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
-public final class MD_CharacterSetCode extends XmlAdapter<MD_CharacterSetCode, Charset> {
+public final class MD_CharacterSetCode extends CodeListAdapter<MD_CharacterSetCode, CharacterSet> {
     /**
-     * The value of the {@link CodeList}.
+     * Empty constructor for JAXB only.
      */
-    private CodeListUID identifier;
-
-    /**
-     * Substitutes the adapter value read from an XML stream by the object which will
-     * contains the value. JAXB calls automatically this method at unmarshalling time.
-     *
-     * @param  adapter The adapter for this metadata value.
-     * @return A code list which represents the metadata value.
-     */
-    @Override
-    public final Charset unmarshal(final MD_CharacterSetCode adapter) throws IllegalCharsetNameException {
-        final Context context = Context.current();
-        return Context.converter(context).toCharset(context, adapter.identifier.toString());
+    public MD_CharacterSetCode() {
     }
 
     /**
-     * Substitutes the code list by the adapter to be marshalled into an XML file
-     * or stream. JAXB calls automatically this method at marshalling time.
-     *
-     * @param  value The code list value.
-     * @return The adapter for the given code list.
+     * Creates a new adapter for the given proxy.
+     */
+    private MD_CharacterSetCode(final CodeListUID value) {
+        super(value);
+    }
+
+    /**
+     * {@inheritDoc}
      */
     @Override
-    public final MD_CharacterSetCode marshal(final Charset value) {
-        final Context context = Context.current();
-        final ValueConverter converter = Context.converter(context);
-        final String code = converter.toCharsetCode(context, value);
-        if (code != null) {
-            final Locale locale = context.getLocale();
-            final MD_CharacterSetCode c = new MD_CharacterSetCode();
-            c.identifier = new CodeListUID(context, "MD_CharacterSetCode", code,
-                    (locale != null) ? converter.toLanguageCode(context, locale) : null,
-                    (locale != null) ? value.displayName(locale) : value.displayName());
-            return c;
-        }
-        return null;
+    protected MD_CharacterSetCode wrap(final CodeListUID value) {
+        return new MD_CharacterSetCode(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Class<CharacterSet> getCodeListClass() {
+        return CharacterSet.class;
     }
 
     /**
@@ -84,6 +67,7 @@
      *
      * @return The value to be marshalled.
      */
+    @Override
     @XmlElement(name = "MD_CharacterSetCode")
     public CodeListUID getElement() {
         return identifier;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_ObligationCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_ObligationCode.java
index 3e7086d..6801e14 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_ObligationCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_ObligationCode.java
@@ -16,9 +16,9 @@
  */
 package org.apache.sis.internal.jaxb.code;
 
-import javax.xml.bind.annotation.XmlElement;
-import org.opengis.annotation.Obligation;
-import org.apache.sis.internal.jaxb.gmd.EnumAdapter;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.metadata.Obligation;
+import org.apache.sis.util.iso.Types;
 
 
 /**
@@ -28,46 +28,32 @@
  *
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
-public final class MD_ObligationCode extends EnumAdapter<MD_ObligationCode, Obligation> {
+public final class MD_ObligationCode extends XmlAdapter<String, Obligation> {
     /**
-     * The enumeration value.
+     * Returns the obligation enumeration for the given name.
+     *
+     * @param value The obligation name.
+     * @return The obligation enumeration for the given name.
      */
-    @XmlElement(name = "MD_ObligationCode")
-    private String value;
-
-    /**
-     * Empty constructor for JAXB only.
-     */
-    public MD_ObligationCode() {
+    @Override
+    public Obligation unmarshal(String value) {
+        return Types.forCodeName(Obligation.class, value, true);
     }
 
     /**
-     * Returns the wrapped value.
+     * Returns the name of the given obligation.
      *
-     * @param wrapper The wrapper.
-     * @return The wrapped value.
+     * @param value The obligation enumeration.
+     * @return The name of the given obligation.
      */
     @Override
-    public final Obligation unmarshal(final MD_ObligationCode wrapper) {
-        return Obligation.valueOf(name(wrapper.value));
-    }
-
-    /**
-     * Wraps the given value.
-     *
-     * @param  e The value to wrap.
-     * @return The wrapped value.
-     */
-    @Override
-    public final MD_ObligationCode marshal(final Obligation e) {
-        if (e == null) {
+    public String marshal(final Obligation value) {
+        if (value == null) {
             return null;
         }
-        final MD_ObligationCode wrapper = new MD_ObligationCode();
-        wrapper.value = value(e);
-        return wrapper;
+        return value.name();
     }
 }
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 ba6e495..91e564c 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.gmd.EnumAdapter;
+import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
+import org.apache.sis.internal.jaxb.gmd.CodeListUID;
 
 
 /**
@@ -28,16 +29,12 @@
  *
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
-public final class MD_PixelOrientationCode extends EnumAdapter<MD_PixelOrientationCode, PixelOrientation> {
-    /**
-     * The enumeration value.
-     */
-    @XmlElement(name = "MD_PixelOrientationCode")
-    private String value;
-
+public final class MD_PixelOrientationCode
+        extends CodeListAdapter<MD_PixelOrientationCode, PixelOrientation>
+{
     /**
      * Empty constructor for JAXB only.
      */
@@ -45,29 +42,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")
+    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 60fbcdb..4058f8a 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.gmd.EnumAdapter;
+import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
+import org.apache.sis.internal.jaxb.gmd.CodeListUID;
 
 
 /**
@@ -30,16 +31,10 @@
  * @author  Guihem Legal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
-public final class MD_TopicCategoryCode extends EnumAdapter<MD_TopicCategoryCode, TopicCategory> {
-    /**
-     * The enumeration value.
-     */
-    @XmlElement(name = "MD_TopicCategoryCode")
-    private String value;
-
+public final class MD_TopicCategoryCode extends CodeListAdapter<MD_TopicCategoryCode, TopicCategory> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -47,29 +42,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")
+    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/PT_Locale.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/PT_Locale.java
index 2be6f10..dd53d71 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/PT_Locale.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/PT_Locale.java
@@ -17,13 +17,14 @@
 package org.apache.sis.internal.jaxb.code;
 
 import java.util.Locale;
-import java.nio.charset.Charset;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.PropertyException;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.adapters.XmlAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.metadata.identification.CharacterSet;
+import org.apache.sis.util.iso.Types;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.gmd.Country;
 import org.apache.sis.internal.jaxb.gmd.LanguageCode;
@@ -104,7 +105,7 @@
          */
         @XmlElement(required = true)
         @XmlJavaTypeAdapter(MD_CharacterSetCode.class)
-        Charset characterEncoding;
+        CharacterSet characterEncoding;
 
         /**
          * Empty constructor for JAXB only.
@@ -140,8 +141,7 @@
                 return;
             }
             if (encoding != null) {
-                final Context context = Context.current();
-                characterEncoding = Context.converter(context).toCharset(context, encoding);
+                characterEncoding = Types.forCodeName(CharacterSet.class, encoding, true);
             }
         }
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_CouplingType.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_CouplingType.java
index df0c7e9..de3420a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_CouplingType.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_CouplingType.java
@@ -17,8 +17,7 @@
 package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.metadata.identification.CouplingType;
-import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeListAdapter;
 import org.apache.sis.internal.jaxb.gmd.CodeListUID;
 import org.apache.sis.xml.Namespaces;
 
@@ -33,7 +32,7 @@
  * @version 0.5
  * @module
  */
-public final class SV_CouplingType extends CodeListAdapter<SV_CouplingType, CouplingType> {
+public final class SV_CouplingType extends UnsupportedCodeListAdapter<SV_CouplingType> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -60,11 +59,11 @@
     /**
      * {@inheritDoc}
      *
-     * @return The code list class.
+     * @return The code list class name.
      */
     @Override
-    protected Class<CouplingType> getCodeListClass() {
-        return CouplingType.class;
+    protected String getCodeListName() {
+        return "SV_CouplingType";
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java
deleted file mode 100644
index c01b7ef..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java
+++ /dev/null
@@ -1,74 +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.jaxb.code;
-
-import javax.xml.bind.annotation.XmlElement;
-import org.opengis.parameter.ParameterDirection;
-import org.apache.sis.internal.jaxb.gmd.EnumAdapter;
-import org.apache.sis.xml.Namespaces;
-
-
-/**
- * JAXB adapter for {@link ParameterDirection}, in order to integrate the value in an element
- * complying with ISO-19139 standard. See package documentation for more information
- * about the handling of {@code CodeList} in ISO-19139.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.5
- * @version 0.5
- * @module
- */
-public final class SV_ParameterDirection extends EnumAdapter<SV_ParameterDirection, ParameterDirection> {
-    /**
-     * The enumeration value.
-     */
-    @XmlElement(name = "SV_ParameterDirection", namespace = Namespaces.SRV)
-    private String value;
-
-    /**
-     * Empty constructor for JAXB only.
-     */
-    public SV_ParameterDirection() {
-    }
-
-    /**
-     * Returns the wrapped value.
-     *
-     * @param wrapper The wrapper.
-     * @return The wrapped value.
-     */
-    @Override
-    public final ParameterDirection unmarshal(final SV_ParameterDirection wrapper) {
-        return ParameterDirection.valueOf(name(wrapper.value));
-    }
-
-    /**
-     * Wraps the given value.
-     *
-     * @param  e The value to wrap.
-     * @return The wrapped value.
-     */
-    @Override
-    public final SV_ParameterDirection marshal(final ParameterDirection e) {
-        if (e == null) {
-            return null;
-        }
-        final SV_ParameterDirection wrapper = new SV_ParameterDirection();
-        wrapper.value = value(e);
-        return wrapper;
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gts/TM_PeriodDuration.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gts/TM_PeriodDuration.java
index 73571c5..3fd7a0d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gts/TM_PeriodDuration.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gts/TM_PeriodDuration.java
@@ -23,7 +23,7 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.datatype.DatatypeConfigurationException;
 import org.opengis.temporal.PeriodDuration;
-import org.opengis.temporal.TemporalFactory;
+import org.apache.sis.internal.geoapi.temporal.TemporalFactory;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.XmlUtilities;
@@ -89,14 +89,15 @@
      */
     @XmlElement(name = "TM_PeriodDuration")
     public Duration getElement() {
-        final PeriodDuration metadata = this.metadata;
-        if (metadata != null) try {
+        if (metadata instanceof org.apache.sis.internal.geoapi.temporal.PeriodDuration) try {
             /*
              * Get the DatatypeFactory first because if not available, then we don't need to parse
              * the calendar fields. This has the side effect of not validating the calendar fields
              * syntax (which should be integer values), but maybe this is what the user wants.
              */
             final DatatypeFactory factory = XmlUtilities.getDatatypeFactory();
+            final org.apache.sis.internal.geoapi.temporal.PeriodDuration metadata =
+                    (org.apache.sis.internal.geoapi.temporal.PeriodDuration) this.metadata;
             InternationalString value;
             BigInteger years = null;
             if ((value = metadata.getYears()) != null) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Party.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Party.java
index 175de29..25f4ff3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Party.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Party.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.citation.Party;
 import org.apache.sis.metadata.iso.citation.AbstractParty;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class CI_Party extends PropertyType<CI_Party, Party> {
+public final class CI_Party extends PropertyType<CI_Party, AbstractParty> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code Party.class}
      */
     @Override
-    protected Class<Party> getBoundType() {
-        return Party.class;
+    protected Class<AbstractParty> getBoundType() {
+        return AbstractParty.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private CI_Party(final Party metadata) {
+    private CI_Party(final AbstractParty metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected CI_Party wrap(final Party metadata) {
+    protected CI_Party wrap(final AbstractParty metadata) {
         return new CI_Party(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public AbstractParty getElement() {
-        return AbstractParty.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Responsibility.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Responsibility.java
index 84281c5..8e049bb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Responsibility.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_Responsibility.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.citation.Responsibility;
 import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
@@ -32,7 +31,7 @@
  * @version 0.5
  * @module
  */
-public final class CI_Responsibility extends PropertyType<CI_Responsibility, Responsibility> {
+public final class CI_Responsibility extends PropertyType<CI_Responsibility, DefaultResponsibility> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -40,21 +39,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code Responsibility.class}
      */
     @Override
-    protected Class<Responsibility> getBoundType() {
-        return Responsibility.class;
+    protected Class<DefaultResponsibility> getBoundType() {
+        return DefaultResponsibility.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private CI_Responsibility(final Responsibility metadata) {
+    private CI_Responsibility(final DefaultResponsibility metadata) {
         super(metadata);
     }
 
@@ -66,7 +63,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected CI_Responsibility wrap(final Responsibility metadata) {
+    protected CI_Responsibility wrap(final DefaultResponsibility metadata) {
         return new CI_Responsibility(metadata);
     }
 
@@ -80,10 +77,10 @@
     @XmlElementRef
     @SuppressWarnings("deprecation")
     public DefaultResponsibility getElement() {
-        if (LEGACY_XML) {
-            return DefaultResponsibleParty.castOrCopy(metadata);
+        if (LEGACY_XML && !(metadata instanceof DefaultResponsibleParty)) {
+            return new DefaultResponsibleParty(metadata);
         } else {
-            return DefaultResponsibility.castOrCopy(metadata);
+            return metadata;
         }
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AssociatedResource.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AssociatedResource.java
deleted file mode 100644
index 2a2b592..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AssociatedResource.java
+++ /dev/null
@@ -1,92 +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.jaxb.metadata;
-
-import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.AssociatedResource;
-import org.apache.sis.metadata.iso.identification.DefaultAssociatedResource;
-import org.apache.sis.internal.jaxb.gco.PropertyType;
-
-
-/**
- * JAXB adapter mapping implementing class to the GeoAPI interface. See
- * package documentation for more information about JAXB and interface.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.5
- * @version 0.5
- * @module
- */
-public final class MD_AssociatedResource extends PropertyType<MD_AssociatedResource, AssociatedResource> {
-    /**
-     * Empty constructor for JAXB only.
-     */
-    public MD_AssociatedResource() {
-    }
-
-    /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
-     *
-     * @return {@code AssociatedResource.class}
-     */
-    @Override
-    protected Class<AssociatedResource> getBoundType() {
-        return AssociatedResource.class;
-    }
-
-    /**
-     * Constructor for the {@link #wrap} method only.
-     */
-    private MD_AssociatedResource(final AssociatedResource metadata) {
-        super(metadata);
-    }
-
-    /**
-     * Invoked by {@link PropertyType} at marshalling time for wrapping the given metadata value
-     * in a {@code <gmd:MD_AssociatedResource>} XML element.
-     *
-     * @param  metadata The metadata element to marshall.
-     * @return A {@code PropertyType} wrapping the given the metadata element.
-     */
-    @Override
-    protected MD_AssociatedResource wrap(final AssociatedResource metadata) {
-        return new MD_AssociatedResource(metadata);
-    }
-
-    /**
-     * Invoked by JAXB at marshalling time for getting the actual metadata to write
-     * inside the {@code <gmd:MD_AssociatedResource>} XML element.
-     * This is the value or a copy of the value given in argument to the {@code wrap} method.
-     *
-     * @return The metadata to be marshalled.
-     */
-    @XmlElementRef
-    public DefaultAssociatedResource getElement() {
-        return DefaultAssociatedResource.castOrCopy(metadata);
-    }
-
-    /**
-     * Invoked by JAXB at unmarshalling time for storing the result temporarily.
-     *
-     * @param metadata The unmarshalled metadata.
-     */
-    public void setElement(final DefaultAssociatedResource metadata) {
-        this.metadata = metadata;
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AttributeGroup.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AttributeGroup.java
index 7dbabae..f44314a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AttributeGroup.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_AttributeGroup.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.content.AttributeGroup;
 import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class MD_AttributeGroup extends PropertyType<MD_AttributeGroup, AttributeGroup> {
+public final class MD_AttributeGroup extends PropertyType<MD_AttributeGroup, DefaultAttributeGroup> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code AttributeGroup.class}
      */
     @Override
-    protected Class<AttributeGroup> getBoundType() {
-        return AttributeGroup.class;
+    protected Class<DefaultAttributeGroup> getBoundType() {
+        return DefaultAttributeGroup.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private MD_AttributeGroup(final AttributeGroup metadata) {
+    private MD_AttributeGroup(final DefaultAttributeGroup metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected MD_AttributeGroup wrap(final AttributeGroup metadata) {
+    protected MD_AttributeGroup wrap(final DefaultAttributeGroup metadata) {
         return new MD_AttributeGroup(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public DefaultAttributeGroup getElement() {
-        return DefaultAttributeGroup.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Identifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Identifier.java
index 455f104..3722406 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Identifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_Identifier.java
@@ -86,11 +86,8 @@
     })
     @SuppressWarnings("deprecation")
     public Identifier getElement() {
-        if (metadata instanceof ImmutableIdentifier) {
-            return (ImmutableIdentifier) metadata;
-        }
         if (metadata instanceof ReferenceIdentifier) {
-            return ImmutableIdentifier.castOrCopy(metadata);
+            return ImmutableIdentifier.castOrCopy((ReferenceIdentifier) metadata);
         }
         return DefaultIdentifier.castOrCopy(metadata);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java
index 528e1a7..a3edd2d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_KeywordClass.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.KeywordClass;
 import org.apache.sis.metadata.iso.identification.DefaultKeywordClass;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class MD_KeywordClass extends PropertyType<MD_KeywordClass, KeywordClass> {
+public final class MD_KeywordClass extends PropertyType<MD_KeywordClass, DefaultKeywordClass> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -46,14 +45,14 @@
      * @return {@code KeywordClass.class}
      */
     @Override
-    protected Class<KeywordClass> getBoundType() {
-        return KeywordClass.class;
+    protected Class<DefaultKeywordClass> getBoundType() {
+        return DefaultKeywordClass.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private MD_KeywordClass(final KeywordClass metadata) {
+    private MD_KeywordClass(final DefaultKeywordClass metadata) {
         super(metadata);
     }
 
@@ -65,7 +64,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected MD_KeywordClass wrap(final KeywordClass metadata) {
+    protected MD_KeywordClass wrap(final DefaultKeywordClass metadata) {
         return new MD_KeywordClass(metadata);
     }
 
@@ -78,7 +77,7 @@
      */
     @XmlElementRef
     public DefaultKeywordClass getElement() {
-        return DefaultKeywordClass.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_MetadataScope.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_MetadataScope.java
index ca499db..d827799 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_MetadataScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/MD_MetadataScope.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.MetadataScope;
 import org.apache.sis.metadata.iso.DefaultMetadataScope;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class MD_MetadataScope extends PropertyType<MD_MetadataScope, MetadataScope> {
+public final class MD_MetadataScope extends PropertyType<MD_MetadataScope, DefaultMetadataScope> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code MetadataScope.class}
      */
     @Override
-    protected Class<MetadataScope> getBoundType() {
-        return MetadataScope.class;
+    protected Class<DefaultMetadataScope> getBoundType() {
+        return DefaultMetadataScope.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private MD_MetadataScope(final MetadataScope metadata) {
+    private MD_MetadataScope(final DefaultMetadataScope metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected MD_MetadataScope wrap(final MetadataScope metadata) {
+    protected MD_MetadataScope wrap(final DefaultMetadataScope metadata) {
         return new MD_MetadataScope(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public DefaultMetadataScope getElement() {
-        return DefaultMetadataScope.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
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 2e4fbfb..d60dc2d 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
@@ -17,14 +17,14 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
 
 /**
- * JAXB adapter in order to map implementing class with the GeoAPI interface. See
- * package documentation for more information about JAXB and interface.
+ * JAXB adapter in order to map implementing class with the GeoAPI interface.
+ * See package documentation for more information about JAXB and interface.
  *
  * @author  Guilhem Legal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -60,7 +60,7 @@
 
     /**
      * Invoked by {@link PropertyType} at marshalling time for wrapping the given metadata value
-     * in a {@code <gmd:DQ_Scope>} XML element.
+     * in a {@code <gmd:MD_Scope>} XML element.
      *
      * @param  metadata The metadata element to marshall.
      * @return A {@code PropertyType} wrapping the given the metadata element.
@@ -72,7 +72,7 @@
 
     /**
      * Invoked by JAXB at marshalling time for getting the actual metadata to write
-     * inside the {@code <gmd:DQ_Scope>} XML element.
+     * inside the {@code <gmd:MD_Scope>} XML element.
      * This is the value or a copy of the value given in argument to the {@code wrap} method.
      *
      * @return The metadata to be marshalled.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/RS_Identifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/RS_Identifier.java
index 40289f2..30e9c85 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/RS_Identifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/RS_Identifier.java
@@ -17,13 +17,13 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
 
 /**
- * JAXB adapter mapping the GeoAPI {@link Identifier} to an implementation class that can
+ * JAXB adapter mapping the GeoAPI {@link ReferenceIdentifier} to an implementation class that can
  * be marshalled. See the package documentation for more information about JAXB and interfaces.
  *
  * <p>The XML produced by this adapter shall be compliant to the ISO 19139 syntax.</p>
@@ -37,7 +37,7 @@
  * @version 0.3
  * @module
  */
-public final class RS_Identifier extends PropertyType<RS_Identifier, Identifier> {
+public final class RS_Identifier extends PropertyType<RS_Identifier, ReferenceIdentifier> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -49,17 +49,17 @@
      * This method is indirectly invoked by the private constructor
      * below, so it shall not depend on the state of this object.
      *
-     * @return {@code Identifier.class}
+     * @return {@code ReferenceIdentifier.class}
      */
     @Override
-    protected Class<Identifier> getBoundType() {
-        return Identifier.class;
+    protected Class<ReferenceIdentifier> getBoundType() {
+        return ReferenceIdentifier.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private RS_Identifier(final Identifier metadata) {
+    private RS_Identifier(final ReferenceIdentifier metadata) {
         super(metadata);
     }
 
@@ -71,7 +71,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected RS_Identifier wrap(Identifier metadata) {
+    protected RS_Identifier wrap(ReferenceIdentifier metadata) {
         return new RS_Identifier(metadata);
     }
 
@@ -84,7 +84,7 @@
      */
     @XmlElementRef
     public ImmutableIdentifier getElement() {
-        final Identifier metadata = this.metadata;
+        final ReferenceIdentifier metadata = this.metadata;
         if (metadata == null) {
             return null;
         } else if (metadata instanceof ImmutableIdentifier) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_CoupledResource.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_CoupledResource.java
index f884ba9..3040709 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_CoupledResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_CoupledResource.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.CoupledResource;
 import org.apache.sis.metadata.iso.identification.DefaultCoupledResource;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class SV_CoupledResource extends PropertyType<SV_CoupledResource, CoupledResource> {
+public final class SV_CoupledResource extends PropertyType<SV_CoupledResource, DefaultCoupledResource> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code CoupledResource.class}
      */
     @Override
-    protected Class<CoupledResource> getBoundType() {
-        return CoupledResource.class;
+    protected Class<DefaultCoupledResource> getBoundType() {
+        return DefaultCoupledResource.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private SV_CoupledResource(final CoupledResource metadata) {
+    private SV_CoupledResource(final DefaultCoupledResource metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected SV_CoupledResource wrap(final CoupledResource metadata) {
+    protected SV_CoupledResource wrap(final DefaultCoupledResource metadata) {
         return new SV_CoupledResource(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public DefaultCoupledResource getElement() {
-        return DefaultCoupledResource.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationChainMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationChainMetadata.java
index 3802405..4bb7013 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationChainMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationChainMetadata.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.OperationChainMetadata;
 import org.apache.sis.metadata.iso.identification.DefaultOperationChainMetadata;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class SV_OperationChainMetadata extends PropertyType<SV_OperationChainMetadata, OperationChainMetadata> {
+public final class SV_OperationChainMetadata extends PropertyType<SV_OperationChainMetadata, DefaultOperationChainMetadata> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code OperationChainMetadata.class}
      */
     @Override
-    protected Class<OperationChainMetadata> getBoundType() {
-        return OperationChainMetadata.class;
+    protected Class<DefaultOperationChainMetadata> getBoundType() {
+        return DefaultOperationChainMetadata.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private SV_OperationChainMetadata(final OperationChainMetadata metadata) {
+    private SV_OperationChainMetadata(final DefaultOperationChainMetadata metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected SV_OperationChainMetadata wrap(final OperationChainMetadata metadata) {
+    protected SV_OperationChainMetadata wrap(final DefaultOperationChainMetadata metadata) {
         return new SV_OperationChainMetadata(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public DefaultOperationChainMetadata getElement() {
-        return DefaultOperationChainMetadata.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationMetadata.java
index c5e0cfc..8cbdc7a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/SV_OperationMetadata.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.metadata;
 
 import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.metadata.identification.OperationMetadata;
 import org.apache.sis.metadata.iso.identification.DefaultOperationMetadata;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.5
  * @module
  */
-public final class SV_OperationMetadata extends PropertyType<SV_OperationMetadata, OperationMetadata> {
+public final class SV_OperationMetadata extends PropertyType<SV_OperationMetadata, DefaultOperationMetadata> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -39,21 +38,19 @@
     }
 
     /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
+     * Returns the type which is bound by this adapter.
      *
      * @return {@code OperationMetadata.class}
      */
     @Override
-    protected Class<OperationMetadata> getBoundType() {
-        return OperationMetadata.class;
+    protected Class<DefaultOperationMetadata> getBoundType() {
+        return DefaultOperationMetadata.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private SV_OperationMetadata(final OperationMetadata metadata) {
+    private SV_OperationMetadata(final DefaultOperationMetadata metadata) {
         super(metadata);
     }
 
@@ -65,7 +62,7 @@
      * @return A {@code PropertyType} wrapping the given the metadata element.
      */
     @Override
-    protected SV_OperationMetadata wrap(final OperationMetadata metadata) {
+    protected SV_OperationMetadata wrap(final DefaultOperationMetadata metadata) {
         return new SV_OperationMetadata(metadata);
     }
 
@@ -78,7 +75,7 @@
      */
     @XmlElementRef
     public DefaultOperationMetadata getElement() {
-        return DefaultOperationMetadata.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
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 f09686f..1de5ab1 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
@@ -18,8 +18,8 @@
 
 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.util.ComparisonMode;
 
@@ -73,7 +73,7 @@
      *
      * @param name The primary name by which this object is identified.
      */
-    public ReferenceSystemMetadata(final Identifier name) {
+    public ReferenceSystemMetadata(final ReferenceIdentifier name) {
         super(name);
     }
 
@@ -84,7 +84,7 @@
      */
     @Override
     @XmlElement(name = "referenceSystemIdentifier")
-    public final Identifier getName() {
+    public final ReferenceIdentifier getName() {
         return super.getName();
     }
 
@@ -93,7 +93,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 ea366f3..0db000d 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
@@ -28,8 +28,8 @@
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 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.metadata.direct.GO_MemberName;
 import org.apache.sis.internal.metadata.ReferencingServices;
@@ -38,7 +38,6 @@
 import org.apache.sis.util.iso.Names;
 import org.apache.sis.xml.Namespaces;
 
-import static org.apache.sis.util.Utilities.deepEquals;
 import static org.apache.sis.internal.util.CollectionsExt.nonNull;
 import static org.apache.sis.internal.jaxb.gco.PropertyType.LEGACY_XML;
 
@@ -72,7 +71,6 @@
 @SuppressWarnings("rawtypes") // For the omission of <T> in ParameterDescriptor<T> - see javadoc.
 @XmlType(name = "SV_Parameter_Type", namespace = Namespaces.SRV, propOrder = {
     "memberName",
-    "direction",
     "description",
     "optionality",
     "repeatability",
@@ -95,12 +93,6 @@
     MemberName memberName;
 
     /**
-     * Indication if the parameter is an input to the service, an output or both.
-     */
-    @XmlElement
-    ParameterDirection direction;
-
-    /**
      * A narrative explanation of the role of the parameter.
      */
     @XmlElement
@@ -147,8 +139,6 @@
     private ServiceParameter(final ParameterDescriptor<?> parameter) {
         super(parameter);
         memberName    = getMemberName(parameter);
-        direction     = parameter.getDirection();
-        description   = parameter.getDescription();
         optionality   = parameter.getMinimumOccurs() > 0;
         repeatability = parameter.getMaximumOccurs() > 1;
     }
@@ -176,7 +166,7 @@
      */
     public static MemberName getMemberName(final ParameterDescriptor<?> parameter) {
         if (parameter != null) {
-            final Identifier id = parameter.getName();
+            final ReferenceIdentifier id = parameter.getName();
             if (id instanceof MemberName) {
                 return (MemberName) id;
             }
@@ -207,10 +197,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);
             }
@@ -242,21 +232,10 @@
     }
 
     /**
-     * Returns an indication if the parameter is an input to the service, an output or both.
-     *
-     * @return Indication if the parameter is an input or output to the service, or {@code null} if unspecified.
-     */
-    @Override
-    public ParameterDirection getDirection() {
-        return direction;
-    }
-
-    /**
      * Returns a narrative explanation of the role of the parameter.
      *
      * @return A narrative explanation of the role of the parameter, or {@code null} if none.
      */
-    @Override
     public InternationalString getDescription() {
         return description;
     }
@@ -350,13 +329,11 @@
                     return Objects.equals(toString(getName()), toString(that.getName()));
                     // super.equals(…) already compared 'getName()' in others mode.
                 }
-                return deepEquals(that.getDescription(), getDescription(), mode) &&
-                                  that.getDirection()     == getDirection()     &&
-                                  that.getMinimumOccurs() == getMinimumOccurs() &&
-                                  that.getMaximumOccurs() == getMaximumOccurs() &&
-                                  that.getValidValues()   == null &&
-                                  that.getMinimumValue()  == null &&
-                                  that.getMaximumValue()  == null;
+                return that.getMinimumOccurs() == getMinimumOccurs() &&
+                       that.getMaximumOccurs() == getMaximumOccurs() &&
+                       that.getValidValues()   == null &&
+                       that.getMinimumValue()  == null &&
+                       that.getMaximumValue()  == null;
             }
         }
         return false;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/package-info.java
index d5b7a86..224c0c0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/package-info.java
@@ -42,7 +42,6 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(RS_Identifier.class),
-    @XmlJavaTypeAdapter(SV_ParameterDirection.class),
 
     // Java types, primitive types and basic OGC types handling
     @XmlJavaTypeAdapter(StringAdapter.class),
@@ -64,5 +63,4 @@
 import org.apache.sis.internal.jaxb.gco.StringAdapter;
 import org.apache.sis.internal.jaxb.gco.InternationalStringAdapter;
 import org.apache.sis.internal.jaxb.metadata.RS_Identifier;
-import org.apache.sis.internal.jaxb.code.SV_ParameterDirection;
 import org.apache.sis.xml.Namespaces;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
index fd17160..50db477 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
@@ -32,7 +32,7 @@
 
 import static org.opengis.referencing.cs.AxisDirection.*;
 import static org.opengis.annotation.Obligation.CONDITIONAL;
-import static org.opengis.annotation.Specification.ISO_19162;
+import static org.opengis.annotation.Specification.UNSPECIFIED;
 import static org.apache.sis.util.CharSequences.*;
 
 
@@ -75,7 +75,7 @@
      *
      * @since 0.7
      */
-    @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=ISO_19162)
+    @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=UNSPECIFIED)
     public static final AxisDirection AWAY_FROM = AxisDirection.valueOf("AWAY_FROM");
 
     /**
@@ -84,7 +84,7 @@
      *
      * @since 0.7
      */
-    @UML(identifier="clockwise", obligation=CONDITIONAL, specification=ISO_19162)
+    @UML(identifier="clockwise", obligation=CONDITIONAL, specification=UNSPECIFIED)
     public static final AxisDirection CLOCKWISE = AxisDirection.valueOf("CLOCKWISE");
 
     /**
@@ -93,7 +93,7 @@
      *
      * @since 0.7
      */
-    @UML(identifier="counterClockwise", obligation=CONDITIONAL, specification=ISO_19162)
+    @UML(identifier="counterClockwise", obligation=CONDITIONAL, specification=UNSPECIFIED)
     public static final AxisDirection COUNTER_CLOCKWISE = AxisDirection.valueOf("COUNTER_CLOCKWISE");
 
     /**
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 ee219ca..451194f 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
@@ -23,6 +23,7 @@
 import org.opengis.util.InternationalString;
 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;
@@ -47,7 +48,7 @@
  * @version 0.7
  * @module
  */
-public final class NameToIdentifier implements Identifier {
+public final class NameToIdentifier implements ReferenceIdentifier {
     /**
      * The name from which to infer the identifier attributes.
      */
@@ -134,16 +135,6 @@
     }
 
     /**
-     * Returns {@code null} since we do not provide natural language description.
-     *
-     * @since 0.5
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
      * Returns a hash code value for this object.
      */
     @Override
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
index e9ef2f4..4d2182a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
@@ -22,7 +22,6 @@
 import javax.measure.unit.Unit;
 import javax.measure.quantity.Length;
 import org.opengis.geometry.Envelope;
-import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.CRSFactory;
@@ -58,6 +57,13 @@
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.Deprecable;
+import org.apache.sis.util.resources.Errors;
+
+// Branch-specific imports
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.DatumFactory;
+import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.util.NoSuchIdentifierException;
 
 
 /**
@@ -400,6 +406,60 @@
     }
 
     /**
+     * Creates a parametric CS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate system name, and optionally other properties.
+     * @param  axis        the axis of the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public CoordinateSystem createParametricCS(final Map<String,?> properties, final CoordinateSystemAxis axis,
+            final CSFactory factory) throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
+     * Creates a parametric datum. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the datum name, and optionally other properties.
+     * @param  factory     the factory to use for creating the datum.
+     * @return a parametric datum using the given name.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public Datum createParametricDatum(final Map<String,?> properties, final DatumFactory factory)
+            throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
+     * Creates a parametric CRS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate reference system name, and optionally other properties.
+     * @param  datum       the parametric datum.
+     * @param  cs          the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate reference system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public SingleCRS createParametricCRS(final Map<String,?> properties, final Datum datum,
+            final CoordinateSystem cs, final CRSFactory factory) throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
      * Creates a derived CRS from the information found in a WKT 1 {@code FITTED_CS} element.
      * This coordinate system can not be easily constructed from the information provided by the WKT 1 format.
      * Note that this method is needed only for WKT 1 parsing, since WKT provides enough information for using
@@ -631,7 +691,7 @@
         {
             final String codespace = identifier.substring(0, s).trim();
             final String code = identifier.substring(++s).trim();
-            for (final Identifier id : method.getIdentifiers()) {
+            for (final ReferenceIdentifier id : method.getIdentifiers()) {
                 if (codespace.equalsIgnoreCase(id.getCodeSpace()) && code.equalsIgnoreCase(id.getCode())) {
                     return true;
                 }
@@ -673,6 +733,29 @@
     }
 
     /**
+     * Returns the coordinate operation method for the given classification.
+     * This method checks if the given {@code opFactory} is a SIS implementation
+     * before to fallback on a slower fallback.
+     *
+     * @param  opFactory  The coordinate operation factory to use if it is a SIS implementation.
+     * @param  mtFactory  The math transform factory to use as a fallback.
+     * @param  identifier The name or identifier of the operation method to search.
+     * @return The coordinate operation method for the given name or identifier.
+     * @throws FactoryException if an error occurred which searching for the given method.
+     *
+     * @since 0.6
+     */
+    public OperationMethod getOperationMethod(final CoordinateOperationFactory opFactory,
+            final MathTransformFactory mtFactory, final String identifier) throws FactoryException
+    {
+        final OperationMethod method = getOperationMethod(mtFactory.getAvailableMethods(SingleOperation.class), identifier);
+        if (method != null) {
+            return method;
+        }
+        throw new NoSuchIdentifierException(Errors.format(Errors.Keys.NoSuchOperationMethod_1, identifier), identifier);
+    }
+
+    /**
      * Returns information about the Apache SIS configuration to be reported in {@link org.apache.sis.setup.About}.
      * This method is invoked only for aspects that depends on other modules than {@code sis-utility}.
      *
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
index 62cb33d..405ca9b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
@@ -24,7 +24,7 @@
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.Responsibility;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.apache.sis.internal.simple.CitationConstant;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.MetadataServices;
@@ -34,7 +34,7 @@
 import org.apache.sis.metadata.iso.citation.Citations;
 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.metadata.iso.citation.DefaultResponsibleParty;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.Exceptions;
@@ -173,13 +173,14 @@
         if (code                  != null) c.setIdentifiers(singleton(new ImmutableIdentifier(null, codeSpace, code, version, null)));
         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) {
             for (final Citation other : copyFrom) {
-                final Collection<? extends Responsibility> parties = other.getCitedResponsibleParties();
-                final Collection<Responsibility> current = c.getCitedResponsibleParties();
+                final Collection<? extends ResponsibleParty> parties = other.getCitedResponsibleParties();
+                final Collection<ResponsibleParty> current = c.getCitedResponsibleParties();
                 if (current != null) {
                     current.addAll(parties);
                 } else {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
index 1d9a5e9..6580717 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
@@ -47,6 +47,7 @@
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.GeneralParameterValue;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.crs.CompoundCRS;
@@ -55,7 +56,7 @@
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.ConcatenatedOperation;
 import org.opengis.referencing.operation.MathTransform;
-import org.opengis.util.ControlledVocabulary;
+import org.opengis.util.CodeList;
 
 import org.apache.sis.measure.Units;
 import org.apache.sis.math.DecimalFunctions;
@@ -789,17 +790,17 @@
         }
         if (showIDs) {
             @SuppressWarnings("null")
-            Collection<? extends Identifier> identifiers = object.getIdentifiers();
+            Collection<ReferenceIdentifier> identifiers = object.getIdentifiers();
             if (identifiers != null) {  // Paranoiac check
                 if (filterID) {
-                    for (final Identifier id : identifiers) {
+                    for (final ReferenceIdentifier id : identifiers) {
                         if (Citations.identifierMatches(authority, id.getAuthority())) {
                             identifiers = Collections.singleton(id);
                             break;
                         }
                     }
                 }
-                for (Identifier id : identifiers) {
+                for (ReferenceIdentifier id : identifiers) {
                     if (!(id instanceof FormattableObject)) {
                         id = ImmutableIdentifier.castOrCopy(id);
                     }
@@ -1105,7 +1106,7 @@
      *
      * @param code The code list to append to the WKT, or {@code null} if none.
      */
-    public void append(final ControlledVocabulary code) {
+    public void append(final CodeList<?> code) {
         if (code != null) {
             appendSeparator();
             final String name = convention.majorVersion() == 1 ? code.name() : Types.getCodeName(code);
@@ -1355,13 +1356,11 @@
             } else {
                 append(number.doubleValue());
             }
-        } else if (value instanceof ControlledVocabulary) {
-            append((ControlledVocabulary) value);
-        } else if (value instanceof Date) {
-            append((Date) value);
-        } else if (value instanceof Boolean) {
-            append((Boolean) value);
-        } else if (value instanceof CharSequence) {
+        }
+        else if (value instanceof CodeList<?>) append((CodeList<?>) value);
+        else if (value instanceof Date)        append((Date)        value);
+        else if (value instanceof Boolean)     append((Boolean)     value);
+        else if (value instanceof CharSequence) {
             append((value instanceof InternationalString) ?
                     ((InternationalString) value).toString(locale) : value.toString(), null);
         } else {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
index 04053ed..fff2691 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -46,6 +46,7 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.referencing.ObjectFactory;
 import org.opengis.util.FactoryException;
@@ -986,7 +987,7 @@
             }
             else if (type.equals(WKTKeywords.parametric)) {
                 if (axes.length == (dimension = 1)) {
-                    return csFactory.createParametricCS(csProperties, axes[0]);
+                    return referencing.createParametricCS(csProperties, axes[0], csFactory);
                 }
             }
             else {
@@ -1289,14 +1290,15 @@
          * not use the identifier.
          */
         FactoryException suppressed = null;
-        if (id != null) try {
+        if (id instanceof ReferenceIdentifier) try {
             // CodeSpace is a mandatory attribute in ID[…] elements, so we do not test for null values.
-            return opFactory.getOperationMethod(id.getCodeSpace() + DefaultNameSpace.DEFAULT_SEPARATOR + id.getCode());
+            return referencing.getOperationMethod(opFactory, mtFactory,
+                    ((ReferenceIdentifier) id).getCodeSpace() + DefaultNameSpace.DEFAULT_SEPARATOR + id.getCode());
         } catch (FactoryException e) {
             suppressed = e;
         }
         try {
-            return opFactory.getOperationMethod(name);
+            return referencing.getOperationMethod(opFactory, mtFactory, name);
         } catch (FactoryException e) {
             if (suppressed != null) {
 //              e.addSuppressed(suppressed);    // Not available on JDK6.
@@ -1500,14 +1502,14 @@
      * @return The {@code "ParametricDatum"} element as a {@link ParametricDatum} object.
      * @throws ParseException if the {@code "ParametricDatum"} element can not be parsed.
      */
-    private ParametricDatum parseParametricDatum(final int mode, final Element parent) throws ParseException {
+    private Datum parseParametricDatum(final int mode, final Element parent) throws ParseException {
         final Element element = parent.pullElement(mode, WKTKeywords.ParametricDatum, WKTKeywords.PDatum);
         if (element == null) {
             return null;
         }
         final String name = element.pullString("name");
         try {
-            return datumFactory.createParametricDatum(parseAnchorAndClose(element, name));
+            return referencing.createParametricDatum(parseAnchorAndClose(element, name), datumFactory);
         } catch (FactoryException exception) {
             throw element.parseFailed(exception);
         }
@@ -2030,7 +2032,7 @@
          * A ParametricCRS can be either a "normal" one (with a non-null datum), or a DerivedCRS of kind ParametricCRS.
          * In the later case, the datum is null and we have instead DerivingConversion element from a BaseParametricCRS.
          */
-        ParametricDatum datum    = null;
+        Datum           datum    = null;
         SingleCRS       baseCRS  = null;
         Conversion      fromBase = null;
         if (!isBaseCRS) {
@@ -2056,11 +2058,11 @@
         try {
             cs = parseCoordinateSystem(element, WKTKeywords.parametric, 1, false, unit, datum);
             final Map<String,?> properties = parseMetadataAndClose(element, name, datum);
-            if (cs instanceof ParametricCS) {
+            if (cs != null) {
                 if (baseCRS != null) {
                     return crsFactory.createDerivedCRS(properties, baseCRS, fromBase, cs);
                 }
-                return crsFactory.createParametricCRS(properties, datum, (ParametricCS) cs);
+                return referencing.createParametricCRS(properties, datum, cs, crsFactory);
             }
         } catch (FactoryException exception) {
             throw element.parseFailed(exception);
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
index 3656b1f..ae295de 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
@@ -30,6 +30,7 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.ExtendedElementInformation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.ComparisonMode;
@@ -116,7 +117,7 @@
      * than GeoAPI, but have a slight performance cost at construction time. Performance
      * after construction should be the same.</p>
      */
-    static final boolean IMPLEMENTATION_CAN_ALTER_API = false;
+    static final boolean IMPLEMENTATION_CAN_ALTER_API = true;
 
     /**
      * Metadata instances defined in this class. The current implementation does not yet
@@ -143,11 +144,12 @@
      */
     public static final MetadataStandard ISO_19123;
     static {
+        final String[] prefix = {"Default", "Abstract"};
         final String[] acronyms = {"CoordinateSystem", "CS", "CoordinateReferenceSystem", "CRS"};
 
         // If new StandardImplementation instances are added below, please update StandardImplementation.readResolve().
-        ISO_19115 = new StandardImplementation("ISO 19115", "org.opengis.metadata.", "org.apache.sis.metadata.iso.", null, null);
-        ISO_19111 = new StandardImplementation("ISO 19111", "org.opengis.referencing.", "org.apache.sis.referencing.", acronyms, new MetadataStandard[] {ISO_19115});
+        ISO_19115 = new StandardImplementation("ISO 19115", "org.opengis.metadata.", "org.apache.sis.metadata.iso.", prefix, null, null);
+        ISO_19111 = new StandardImplementation("ISO 19111", "org.opengis.referencing.", "org.apache.sis.referencing.", prefix, acronyms, new MetadataStandard[] {ISO_19115});
         ISO_19123 = new MetadataStandard      ("ISO 19123", "org.opengis.coverage.", new MetadataStandard[] {ISO_19111});
         INSTANCES = new MetadataStandard[] {
             ISO_19111,
@@ -656,10 +658,10 @@
      * <p>In the particular case of Apache SIS implementation, all values in the information map
      * additionally implement the following interfaces:</p>
      * <ul>
-     *   <li>{@link Identifier} with the following properties:
+     *   <li>{@link ReferenceIdentifier} with the following properties:
      *     <ul>
      *       <li>The {@linkplain Identifier#getAuthority() authority} is this metadata standard {@linkplain #getCitation() citation}.</li>
-     *       <li>The {@linkplain Identifier#getCodeSpace() codespace} is the standard name of the interface that contain the property.</li>
+     *       <li>The {@linkplain ReferenceIdentifier#getCodeSpace() codespace} is the standard name of the interface that contain the property.</li>
      *       <li>The {@linkplain Identifier#getCode() code} is the standard name of the property.</li>
      *     </ul>
      *   </li>
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 84da5eb..bd6a9be 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;
@@ -323,7 +323,6 @@
     /**
      * Unconditionally returns {@code null}.
      */
-    @Override
     public InternationalString getRationale() {
         return null;
     }
@@ -341,7 +340,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/Pruner.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/Pruner.java
index b160d01..332593f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/Pruner.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/Pruner.java
@@ -19,7 +19,7 @@
 import java.util.Map;
 import java.util.Iterator;
 import java.util.Collection;
-import org.opengis.util.ControlledVocabulary;
+import org.opengis.util.CodeList;
 import org.apache.sis.util.Emptiable;
 import org.apache.sis.internal.util.CollectionsExt;
 
@@ -172,7 +172,7 @@
                         } else if (!prune && element instanceof Emptiable) {
                             isEmptyElement = ((Emptiable) element).isEmpty();
                             // If 'prune' is true, we will rather test for Emptiable after our pruning attempt.
-                        } else if (!(element instanceof ControlledVocabulary)) {
+                        } else if (!(element instanceof Enum<?>) && !(element instanceof CodeList<?>)) {
                             final MetadataStandard standard = MetadataStandard.forClass(element.getClass());
                             if (standard != null) {
                                 isEmptyElement = isEmpty(asMap(standard, element, false, prune), tested, prune);
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
index 0c6e149..dafd153 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/SpecialCases.java
@@ -31,7 +31,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.4
  * @module
  */
 final class SpecialCases extends PropertyAccessor {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
index 94441f6..df5a9a5 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
@@ -19,8 +19,6 @@
 import java.util.Map;
 import java.util.IdentityHashMap;
 import org.opengis.annotation.UML;
-import org.opengis.annotation.Classifier;
-import org.opengis.annotation.Stereotype;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.internal.system.Modules;
@@ -47,6 +45,12 @@
     private final String implementationPackage;
 
     /**
+     * The prefixes that implementation classes may have.
+     * The most common prefixes should be first, since the prefixes will be tried in that order.
+     */
+    private final String[] prefix;
+
+    /**
      * The acronyms that implementation classes may have, or {@code null} if none. If non-null,
      * then this array shall contain (<var>full text</var>, <var>acronym</var>) pairs. The full
      * text shall appear to the end of the class name, otherwise it is not replaced. This is
@@ -74,30 +78,21 @@
      * @param citation              The title of the standard.
      * @param interfacePackage      The root package for metadata interfaces, with a trailing {@code '.'}.
      * @param implementationPackage The root package for metadata implementations. with a trailing {@code '.'}.
+     * @param prefix                The prefix of implementation class. This array is not cloned.
      * @param acronyms              An array of (full text, acronyms) pairs. This array is not cloned.
      * @param dependencies          The dependencies to other metadata standards, or {@code null} if none.
      */
     StandardImplementation(final String citation, final String interfacePackage, final String implementationPackage,
-            final String[] acronyms, final MetadataStandard[] dependencies)
+            final String[] prefix, final String[] acronyms, final MetadataStandard[] dependencies)
     {
         super(citation, interfacePackage, dependencies);
         this.implementationPackage = implementationPackage;
+        this.prefix                = prefix;
         this.acronyms              = acronyms;
         this.implementations       = new IdentityHashMap<Class<?>,Class<?>>();
     }
 
     /**
-     * Returns {@code true} if the given type is conceptually abstract.
-     * The given type is usually an interface, so here "abstract" can not be in the Java sense.
-     * If this method can not find information about whether the given type is abstract,
-     * then this method conservatively returns {@code false}.
-     */
-    private static boolean isAbstract(final Class<?> type) {
-        final Classifier c = type.getAnnotation(Classifier.class);
-        return (c != null) && c.value() == Stereotype.ABSTRACT;
-    }
-
-    /**
      * Accepts Apache SIS implementation classes as "pseudo-interfaces" if they are annotated with {@link UML}.
      * We use this feature for example in the transition from ISO 19115:2003 to ISO 19115:2014, when new API is
      * defined in Apache SIS but not yet available in GeoAPI interfaces.
@@ -147,18 +142,30 @@
                         }
                     }
                     /*
-                     * Try to instantiate the implementation class.
+                     * Try to insert a prefix in front of the class name, until a match is found.
                      */
                     final int prefixPosition = buffer.lastIndexOf(".") + 1;
-                    buffer.insert(prefixPosition, isAbstract(type) ? "Abstract" : "Default");
-                    classname = buffer.toString();
-                    try {
-                        candidate = Class.forName(classname);
+                    int length = 0;
+                    for (final String p : prefix) {
+                        classname = buffer.replace(prefixPosition, prefixPosition + length, p).toString();
+                        try {
+                            candidate = Class.forName(classname);
+                        } catch (ClassNotFoundException e) {
+                            Logging.recoverableException(Logging.getLogger(Modules.METADATA),
+                                    MetadataStandard.class, "getImplementation", e);
+                            length = p.length();
+                            continue;
+                        }
+                        if (candidate.isAnnotationPresent(Deprecated.class)) {
+                            // Skip deprecated implementations.
+                            candidate = candidate.getSuperclass();
+                            if (!type.isAssignableFrom(candidate) || candidate.isAnnotationPresent(Deprecated.class)) {
+                                length = p.length();
+                                continue;
+                            }
+                        }
                         implementations.put(type, candidate);
                         return candidate.asSubclass(type);
-                    } catch (ClassNotFoundException e) {
-                        Logging.recoverableException(Logging.getLogger(Modules.METADATA),
-                                MetadataStandard.class, "getImplementation", e);
                     }
                     implementations.put(type, Void.TYPE); // Marker for "class not found".
                 }
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 bd513b2..e691e89 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;
@@ -47,9 +48,9 @@
     "name",
     "schemaLanguage",
     "constraintLanguage",
-/// "schemaAscii",
-/// "graphicsFile",
-/// "softwareDevelopmentFile",
+    "schemaAscii",
+    "graphicsFile",
+    "softwareDevelopmentFile",
     "softwareDevelopmentFileFormat"
 })
 @XmlRootElement(name = "MD_ApplicationSchemaInformation")
@@ -59,7 +60,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.
@@ -79,17 +80,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.
@@ -231,20 +232,28 @@
     /**
      * 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")
-    public CharSequence getSchemaAscii()  {
+    @XmlElement(name = "schemaAscii")
+    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 = newValue;
     }
@@ -252,20 +261,30 @@
     /**
      * 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")
-    public OnlineResource getGraphicsFile()  {
+    @XmlElement(name = "graphicsFile")
+    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 = newValue;
     }
@@ -273,20 +292,30 @@
     /**
      * 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")
-    public OnlineResource getSoftwareDevelopmentFile()  {
+    @XmlElement(name = "softwareDevelopmentFile")
+    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 = 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 d5367ab..638672a 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
@@ -16,15 +16,14 @@
  */
 package org.apache.sis.metadata.iso;
 
-import java.util.AbstractSet;
 import java.util.Collection;
-import java.util.Iterator;
 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.annotation.UML;
 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.measure.ValueRange;
@@ -33,6 +32,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * New metadata element, not found in ISO 19115, which is required to describe geographic data.
@@ -76,7 +79,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.
@@ -151,12 +154,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.
@@ -181,7 +184,7 @@
                                              final Datatype     dataType,
                                              final String       parentEntity,
                                              final CharSequence rule,
-                                             final Responsibility source)
+                                             final ResponsibleParty source)
     {
         this.name         = name;
         this.definition   = Types.toInternationalString(definition);
@@ -189,7 +192,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);
     }
 
     /**
@@ -223,8 +226,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);
         }
     }
 
@@ -519,9 +522,10 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="rationale", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getRationale() {
-        return rationale;
+        return LegacyPropertyAdapter.getSingleton(rationales, InternationalString.class, null,
+                DefaultExtendedElementInformation.class, "getRationale");
     }
 
     /**
@@ -532,8 +536,7 @@
      * @since 0.5
      */
     public void setRationale(final InternationalString newValue) {
-        checkWritePermission();
-        rationale = newValue;
+        rationales = writeCollection(LegacyPropertyAdapter.asCollection(newValue), rationales, InternationalString.class);
     }
 
     /**
@@ -545,29 +548,7 @@
     @Deprecated
     @XmlElement(name = "rationale")
     public Collection<InternationalString> getRationales() {
-        return new AbstractSet<InternationalString>() {
-            /** Returns 0 if empty, or 1 if a density has been specified. */
-            @Override public int size() {
-                return getRationale() != null ? 1 : 0;
-            }
-
-            /** Returns an iterator over 0 or 1 element. Current iterator implementation is unmodifiable. */
-            @Override public Iterator<InternationalString> iterator() {
-                return LegacyPropertyAdapter.asCollection(getRationale()).iterator();
-            }
-
-            /** Adds an element only if the set is empty. This method is invoked by JAXB at unmarshalling time. */
-            @Override public boolean add(final InternationalString newValue) {
-                if (isEmpty()) {
-                    setRationale(newValue);
-                    return true;
-                } else {
-                    LegacyPropertyAdapter.warnIgnoredExtraneous(InternationalString.class,
-                            DefaultExtendedElementInformation.class, "setRationales");
-                    return false;
-                }
-            }
-        };
+        return rationales = nonNullCollection(rationales, InternationalString.class);
     }
 
     /**
@@ -577,27 +558,36 @@
      */
     @Deprecated
     public void setRationales(final Collection<? extends InternationalString> newValues) {
-        setRationale(LegacyPropertyAdapter.getSingleton(newValues, InternationalString.class,
-                null, DefaultExtendedElementInformation.class, "setRationales"));
+        rationales = writeCollection(newValues, rationales, InternationalString.class);
     }
 
     /**
      * 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 {@link 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 {@link 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/DefaultIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
index 583eac5..b5e4a57 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
@@ -19,11 +19,16 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.util.Citations;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Value uniquely identifying an object within a namespace.
@@ -188,10 +193,17 @@
         super(object);
         if (object != null) {
             code        = object.getCode();
-            codeSpace   = object.getCodeSpace();
-            version     = object.getVersion();
-            description = object.getDescription();
             authority   = object.getAuthority();
+            if (object instanceof DefaultIdentifier) {
+                final DefaultIdentifier c = (DefaultIdentifier) object;
+                codeSpace   = c.getCodeSpace();
+                version     = c.getVersion();
+                description = c.getDescription();
+            } else if (object instanceof ReferenceIdentifier) {
+                final ReferenceIdentifier c = (ReferenceIdentifier) object;
+                codeSpace = c.getCodeSpace();
+                version   = c.getVersion();
+            }
         }
     }
 
@@ -281,7 +293,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="codeSpace", obligation=OPTIONAL, specification=ISO_19115)
     public String getCodeSpace() {
         return codeSpace;
     }
@@ -307,7 +319,7 @@
      *
      * @return The version identifier for the namespace, or {@code null} if none.
      */
-    @Override
+    @UML(identifier="version", obligation=OPTIONAL, specification=ISO_19115)
     public String getVersion() {
         return version;
     }
@@ -331,7 +343,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="description", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDescription() {
         return description;
     }
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 f40979c..b732218 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
@@ -31,9 +31,9 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.Metadata;
-import org.opengis.metadata.MetadataScope;
 import org.opengis.metadata.ApplicationSchemaInformation;
 import org.opengis.metadata.MetadataExtensionInformation;
 import org.opengis.metadata.PortrayalCatalogueReference;
@@ -42,7 +42,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;
@@ -69,6 +69,11 @@
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.xml.Namespaces;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Root entity which defines metadata about a resource or resources.
@@ -129,7 +134,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -4935599812744534502L;
+    private static final long serialVersionUID = 7337533776231004504L;
 
     /**
      * Unique identifier for this metadata record, or {@code null} if none.
@@ -154,12 +159,12 @@
     /**
      * Scope to which the metadata applies.
      */
-    private Collection<MetadataScope> metadataScopes;
+    private Collection<DefaultMetadataScope> metadataScopes;
 
     /**
      * Parties responsible for the metadata information.
      */
-    private Collection<Responsibility> contacts;
+    private Collection<ResponsibleParty> contacts;
 
     /**
      * Date(s) associated with the metadata.
@@ -215,7 +220,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).
@@ -265,11 +270,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,
-                           final Date           dateStamp,
-                           final Identification identificationInfo)
+    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);
@@ -288,30 +293,49 @@
     public DefaultMetadata(final Metadata object) {
         super(object);
         if (object != null) {
-            metadataIdentifier            = object.getMetadataIdentifier();
-            parentMetadata                = object.getParentMetadata();
-            languages                     = copyCollection(object.getLanguages(),                     Locale.class);
-            characterSets                 = copyCollection(object.getCharacterSets(),                 Charset.class);
-            metadataScopes                = copyCollection(object.getMetadataScopes(),                MetadataScope.class);
-            contacts                      = copyCollection(object.getContacts(),                      Responsibility.class);
-            dateInfo                      = copyCollection(object.getDateInfo(),                      CitationDate.class);
-            metadataStandards             = copyCollection(object.getMetadataStandards(),             Citation.class);
-            metadataProfiles              = copyCollection(object.getMetadataProfiles(),              Citation.class);
-            alternativeMetadataReferences = copyCollection(object.getAlternativeMetadataReferences(), Citation.class);
-            metadataLinkages              = copyCollection(object.getMetadataLinkages(),              OnlineResource.class);
+            contacts                      = copyCollection(object.getContacts(),                      ResponsibleParty.class);
             spatialRepresentationInfo     = copyCollection(object.getSpatialRepresentationInfo(),     SpatialRepresentation.class);
             referenceSystemInfo           = copyCollection(object.getReferenceSystemInfo(),           ReferenceSystem.class);
             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);
             applicationSchemaInfo         = copyCollection(object.getApplicationSchemaInfo(),         ApplicationSchemaInformation.class);
             metadataMaintenance           = object.getMetadataMaintenance();
             acquisitionInformation        = copyCollection(object.getAcquisitionInformation(),        AcquisitionInformation.class);
-            resourceLineages              = copyCollection(object.getResourceLineages(),              Lineage.class);
+            if (object instanceof DefaultMetadata) {
+                final DefaultMetadata c = (DefaultMetadata) object;
+                metadataIdentifier            = c.getMetadataIdentifier();
+                parentMetadata                = c.getParentMetadata();
+                languages                     = copyCollection(c.getLanguages(),                     Locale.class);
+                characterSets                 = copyCollection(c.getCharacterSets(),                 Charset.class);
+                metadataScopes                = copyCollection(c.getMetadataScopes(),                DefaultMetadataScope.class);
+                dateInfo                      = copyCollection(c.getDateInfo(),                      CitationDate.class);
+                metadataStandards             = copyCollection(c.getMetadataStandards(),             Citation.class);
+                metadataProfiles              = copyCollection(c.getMetadataProfiles(),              Citation.class);
+                alternativeMetadataReferences = copyCollection(c.getAlternativeMetadataReferences(), Citation.class);
+                metadataLinkages              = copyCollection(c.getMetadataLinkages(),              OnlineResource.class);
+                resourceLineages              = copyCollection(c.getResourceLineages(),              Lineage.class);
+            } else {
+                setFileIdentifier         (object.getFileIdentifier());
+                setParentIdentifier       (object.getParentIdentifier());
+                setLanguage               (object.getLanguage());
+                setLocales                (object.getLocales());
+                setCharacterSet           (object.getCharacterSet());
+                setHierarchyLevels        (object.getHierarchyLevels());
+                setHierarchyLevelNames    (object.getHierarchyLevelNames());
+                setDateStamp              (object.getDateStamp());
+                setMetadataStandardName   (object.getMetadataStandardName());
+                setMetadataStandardVersion(object.getMetadataStandardVersion());
+                try {
+                    setDataSetUri(object.getDataSetUri());
+                } catch (URISyntaxException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
         }
     }
 
@@ -360,7 +384,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="metadataIdentifier", obligation=OPTIONAL, specification=ISO_19115)
     public Identifier getMetadataIdentifier() {
         return metadataIdentifier;
     }
@@ -428,7 +452,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="defaultLocale+otherLocale", obligation=CONDITIONAL, specification=ISO_19115)
     public Collection<Locale> getLanguages() {
         return languages = nonNullCollection(languages, Locale.class);
     }
@@ -535,7 +559,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="characterSet", obligation=CONDITIONAL, specification=ISO_19115) // Actually from ISO 19115:2003
     public Collection<Charset> getCharacterSets() {
         return characterSets = nonNullCollection(characterSets, Charset.class);
     }
@@ -598,7 +622,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="parentMetadata", obligation=CONDITIONAL, specification=ISO_19115)
     public Citation getParentMetadata() {
         return parentMetadata;
     }
@@ -657,24 +681,34 @@
     /**
      * Returns the scope or type of resource for which metadata is provided.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code MetadataScope} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Scope or type of resource for which metadata is provided.
      *
      * @since 0.5
      */
-    @Override
-    public Collection<MetadataScope> getMetadataScopes() {
-        return metadataScopes = nonNullCollection(metadataScopes, MetadataScope.class);
+    @UML(identifier="metadataScope", obligation=CONDITIONAL, specification=ISO_19115)
+    public Collection<DefaultMetadataScope> getMetadataScopes() {
+        return metadataScopes = nonNullCollection(metadataScopes, DefaultMetadataScope.class);
     }
 
     /**
      * Sets the scope or type of resource for which metadata is provided.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code MetadataScope} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new scope or type of resource.
      *
      * @since 0.5
      */
-    public void setMetadataScopes(final Collection<? extends MetadataScope> newValues) {
-        metadataScopes = writeCollection(newValues, metadataScopes, MetadataScope.class);
+    public void setMetadataScopes(final Collection<? extends DefaultMetadataScope> newValues) {
+        metadataScopes = writeCollection(newValues, metadataScopes, DefaultMetadataScope.class);
     }
 
     /**
@@ -691,22 +725,19 @@
     public final Collection<ScopeCode> getHierarchyLevels() {
         return new MetadataScopeAdapter<ScopeCode>(getMetadataScopes()) {
             /** Stores a legacy value into the new kind of value. */
-            @Override protected MetadataScope wrap(final ScopeCode value) {
+            @Override protected DefaultMetadataScope wrap(final ScopeCode value) {
                 return new DefaultMetadataScope(value, null);
             }
 
             /** Extracts the legacy value from the new kind of value. */
-            @Override protected ScopeCode unwrap(final MetadataScope container) {
+            @Override protected ScopeCode unwrap(final DefaultMetadataScope container) {
                 return container.getResourceScope();
             }
 
             /** Updates the legacy value in an existing instance of the new kind of value. */
-            @Override protected boolean update(final MetadataScope container, final ScopeCode value) {
-                if (container instanceof DefaultMetadataScope) {
-                    ((DefaultMetadataScope) container).setResourceScope(value);
-                    return true;
-                }
-                return false;
+            @Override protected boolean update(final DefaultMetadataScope container, final ScopeCode value) {
+                container.setResourceScope(value);
+                return true;
             }
         }.validOrNull();
     }
@@ -739,23 +770,20 @@
     public final Collection<String> getHierarchyLevelNames() {
         return new MetadataScopeAdapter<String>(getMetadataScopes()) {
             /** Stores a legacy value into the new kind of value. */
-            @Override protected MetadataScope wrap(final String value) {
+            @Override protected DefaultMetadataScope wrap(final String value) {
                 return new DefaultMetadataScope(null, value);
             }
 
             /** Extracts the legacy value from the new kind of value. */
-            @Override protected String unwrap(final MetadataScope container) {
+            @Override protected String unwrap(final DefaultMetadataScope container) {
                 final InternationalString name = container.getName();
                 return (name != null) ? name.toString() : null;
             }
 
             /** Updates the legacy value in an existing instance of the new kind of value. */
-            @Override protected boolean update(final MetadataScope container, final String value) {
-                if (container instanceof DefaultMetadataScope) {
-                    ((DefaultMetadataScope) container).setName(value != null ? new SimpleInternationalString(value) : null);
-                    return true;
-                }
-                return false;
+            @Override protected boolean update(final DefaultMetadataScope container, final String value) {
+                container.setName(value != null ? new SimpleInternationalString(value) : null);
+                return true;
             }
         }.validOrNull();
     }
@@ -777,12 +805,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 {@link 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);
     }
 
     /**
@@ -790,9 +823,9 @@
      *
      * @param newValues The new contacts.
      */
-    public void setContacts(final Collection<? extends Responsibility> newValues) {
+    public void setContacts(final Collection<? extends ResponsibleParty> newValues) {
         checkWritePermission();
-        contacts = writeCollection(newValues, contacts, Responsibility.class);
+        contacts = writeCollection(newValues, contacts, ResponsibleParty.class);
     }
 
     /**
@@ -804,7 +837,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="dateInfo", obligation=MANDATORY, specification=ISO_19115)
     public Collection<CitationDate> getDateInfo() {
         return dateInfo = nonNullCollection(dateInfo, CitationDate.class);
     }
@@ -892,7 +925,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="metadataStandard", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getMetadataStandards() {
         return metadataStandards = nonNullCollection(metadataStandards, Citation.class);
     }
@@ -919,7 +952,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="metadataProfile", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getMetadataProfiles() {
         return metadataProfiles = nonNullCollection(metadataProfiles, Citation.class);
     }
@@ -943,7 +976,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="alternativeMetadataReference", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getAlternativeMetadataReferences() {
         return alternativeMetadataReferences = nonNullCollection(alternativeMetadataReferences, Citation.class);
     }
@@ -1064,7 +1097,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="metadataLinkage", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<OnlineResource> getMetadataLinkages() {
         return metadataLinkages = nonNullCollection(metadataLinkages, OnlineResource.class);
     }
@@ -1097,8 +1130,8 @@
         if (info != null) {
             for (final Identification identification : info) {
                 final Citation citation = identification.getCitation();
-                if (citation != null) {
-                    final Collection<? extends OnlineResource> onlineResources = citation.getOnlineResources();
+                if (citation instanceof DefaultCitation) {
+                    final Collection<? extends OnlineResource> onlineResources = ((DefaultCitation) citation).getOnlineResources();
                     if (onlineResources != null) {
                         for (final OnlineResource link : onlineResources) {
                             final URI uri = link.getLinkage();
@@ -1261,21 +1294,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<? extends 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 = newValue;
     }
 
     /**
@@ -1406,7 +1450,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="resourceLineage", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Lineage> getResourceLineages() {
         return resourceLineages = nonNullCollection(resourceLineages, Lineage.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
index 736e1c1..d4cce4d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
@@ -20,14 +20,27 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.MetadataScope;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.apache.sis.util.iso.Types;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the scope of the resource.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code MetadataScope} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -48,7 +61,8 @@
     "name"
 })
 @XmlRootElement(name = "MD_MetadataScope")
-public class DefaultMetadataScope extends ISOMetadata implements MetadataScope {
+@UML(identifier="MD_MetadataScope", specification=ISO_19115)
+public class DefaultMetadataScope extends ISOMetadata {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -87,10 +101,8 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(MetadataScope)
      */
-    public DefaultMetadataScope(final MetadataScope object) {
+    public DefaultMetadataScope(final DefaultMetadataScope object) {
         super(object);
         if (object != null) {
             resourceScope = object.getResourceScope();
@@ -99,37 +111,12 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultMetadataScope}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultMetadataScope} instance is created using the
-     *       {@linkplain #DefaultMetadataScope(MetadataScope) copy constructor} and returned.
-     *       Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultMetadataScope castOrCopy(final MetadataScope object) {
-        if (object == null || object instanceof DefaultMetadataScope) {
-            return (DefaultMetadataScope) object;
-        }
-        return new DefaultMetadataScope(object);
-    }
-
-    /**
      * Return the code for the scope.
      *
      * @return The ode for the scope.
      */
-    @Override
     @XmlElement(name = "resourceScope", required = true)
+    @UML(identifier="resourceScope", obligation=MANDATORY, specification=ISO_19115)
     public ScopeCode getResourceScope() {
         return resourceScope;
     }
@@ -149,8 +136,8 @@
      *
      * @return Description of the scope, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "name")
+    @UML(identifier="name", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getName() {
         return name;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
index dfdc26c..848b8fb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.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.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.parameter.ParameterValue;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.Types;
@@ -135,13 +135,19 @@
     "version"
 })
 @XmlRootElement(name = "RS_Identifier")
-public class ImmutableIdentifier extends FormattableObject implements Identifier, Serializable {
+public class ImmutableIdentifier extends FormattableObject implements ReferenceIdentifier, Serializable {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = -7681717592582493409L;
 
     /**
+     * Key for the {@value} property in the map to be given to the constructor.
+     * This can be used for setting the value to be returned by {@link #getDescription()}.
+     */
+    public static final String DESCRIPTION_KEY = "description";
+
+    /**
      * The person or party responsible for maintenance of the namespace, or {@code null} if not available.
      *
      * @see #getAuthority()
@@ -187,13 +193,17 @@
      *
      * @param identifier The identifier to copy.
      */
-    public ImmutableIdentifier(final Identifier identifier) {
+    public ImmutableIdentifier(final ReferenceIdentifier identifier) {
         ensureNonNull("identifier", identifier);
-        code        = identifier.getCode();
-        codeSpace   = identifier.getCodeSpace();
-        authority   = identifier.getAuthority();
-        version     = identifier.getVersion();
-        description = identifier.getDescription();
+        code      = identifier.getCode();
+        codeSpace = identifier.getCodeSpace();
+        authority = identifier.getAuthority();
+        version   = identifier.getVersion();
+        if (identifier instanceof DefaultIdentifier) {
+            description = ((DefaultIdentifier) identifier).getDescription();
+        } else {
+            description = null;
+        }
         validate(null);
     }
 
@@ -258,7 +268,7 @@
      *     <td>{@link #getCode()}</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 #getCodeSpace()}</td>
      *   </tr>
@@ -268,12 +278,12 @@
      *     <td>{@link #getAuthority()}</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 #getVersion()}</td>
      *   </tr>
      *   <tr>
-     *     <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
+     *     <td>"description"</td>
      *     <td>{@link String} or {@link InternationalString}</td>
      *     <td>{@link #getDescription()}</td>
      *   </tr>
@@ -360,7 +370,7 @@
      *   <li>Otherwise if the given object is already an instance of
      *       {@code ImmutableIdentifier}, then it is returned unchanged.</li>
      *   <li>Otherwise a new {@code ImmutableIdentifier} instance is created using the
-     *       {@linkplain #ImmutableIdentifier(Identifier) copy constructor} and returned.
+     *       {@linkplain #ImmutableIdentifier(ReferenceIdentifier) copy constructor} and returned.
      *       Note that this is a <cite>shallow</cite> copy operation, since the other
      *       metadata contained in the given object are not recursively copied.</li>
      * </ul>
@@ -369,7 +379,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 ImmutableIdentifier castOrCopy(final Identifier object) {
+    public static ImmutableIdentifier castOrCopy(final ReferenceIdentifier object) {
         if (object == null || object instanceof ImmutableIdentifier) {
             return (ImmutableIdentifier) object;
         }
@@ -441,7 +451,6 @@
      *
      * @since 0.5
      */
-    @Override
     public InternationalString getDescription() {
         return description;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/MetadataScopeAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/MetadataScopeAdapter.java
index b01dc13..fd9fd54 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/MetadataScopeAdapter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/MetadataScopeAdapter.java
@@ -21,7 +21,6 @@
 import java.util.Iterator;
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
-import org.opengis.metadata.MetadataScope;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
 
@@ -35,11 +34,11 @@
  * @version 0.5
  * @module
  */
-abstract class MetadataScopeAdapter<L> extends LegacyPropertyAdapter<L,MetadataScope> {
+abstract class MetadataScopeAdapter<L> extends LegacyPropertyAdapter<L,DefaultMetadataScope> {
     /**
      * @param scopes Value of {@link DefaultMetadata#getMetadataScopes()}.
      */
-    MetadataScopeAdapter(final Collection<MetadataScope> scopes) {
+    MetadataScopeAdapter(final Collection<DefaultMetadataScope> scopes) {
         super(scopes);
     }
 
@@ -51,9 +50,9 @@
     @Override
     public boolean add(final L newValue) {
         int n = 0;
-        final Iterator<MetadataScope> it = elements.iterator();
+        final Iterator<DefaultMetadataScope> it = elements.iterator();
         while (it.hasNext()) {
-            MetadataScope scope = it.next();
+            DefaultMetadataScope scope = it.next();
             if (unwrap(scope) != null) {
                 n++;
                 continue;
@@ -64,16 +63,16 @@
              * But if the metadata is not modifiable, then we will need to clone it and replaces the element in
              * the collection.
              */
-            if (!(scope instanceof DefaultMetadataScope) || !((DefaultMetadataScope) scope).isModifiable()) {
+            if (!scope.isModifiable()) {
                 scope = new DefaultMetadataScope(scope);
                 if (elements instanceof List<?>) {
-                    ((List<MetadataScope>) elements).set(n, scope);
+                    ((List<DefaultMetadataScope>) elements).set(n, scope);
                 } else {
                     /*
                      * Not a list. Delete all the remaining parts, substitute the value
                      * and reinsert everything in the same order.
                      */
-                    final MetadataScope[] remaining = new MetadataScope[elements.size() - n];
+                    final DefaultMetadataScope[] remaining = new DefaultMetadataScope[elements.size() - n];
                     remaining[0] = scope;
                     n = 1;
                     it.remove();
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 a1f6fd6..124e2bf 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;
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
@@ -75,7 +75,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.
@@ -103,7 +103,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);
         }
     }
@@ -200,21 +200,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 {@link 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 {@link 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 f311b28..771cf0b 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 org.apache.sis.internal.jaxb.NonMarshalledAuthority;
 
@@ -78,12 +78,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.
@@ -126,8 +126,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());
@@ -207,41 +207,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 {@link 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 {@link 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 {@link 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 {@link 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 88051eb..f58f490 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
@@ -99,7 +99,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GM_Object.class),
     @XmlJavaTypeAdapter(MD_Identifier.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
index f7a8b06..a7855d4 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
@@ -23,16 +23,27 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Contact;
-import org.opengis.metadata.citation.Individual;
-import org.opengis.metadata.citation.Organisation;
-import org.opengis.metadata.citation.Party;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the individual and / or organization of the party.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code Party} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -57,7 +68,8 @@
     DefaultIndividual.class,
     DefaultOrganisation.class
 })
-public class AbstractParty extends ISOMetadata implements Party {
+@UML(identifier="CI_Party", specification=ISO_19115)
+public class AbstractParty extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -96,10 +108,8 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(Party)
      */
-    public AbstractParty(final Party object) {
+    public AbstractParty(final AbstractParty object) {
         super(object);
         if (object != null) {
             name        = object.getName();
@@ -108,47 +118,12 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is an instance of {@link Individual} or {@link Organisation},
-     *       then this method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass.
-     *       Note that if the given object implements more than one of the above-cited interfaces,
-     *       then the {@code castOrCopy(…)} method to be used is unspecified.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code AbstractParty}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code AbstractParty} instance is created using the
-     *       {@linkplain #AbstractParty(Party) copy constructor} and returned.
-     *       Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 AbstractParty castOrCopy(final Party object) {
-        if (object instanceof Individual) {
-            return DefaultIndividual.castOrCopy((Individual) object);
-        }
-        if (object instanceof Organisation) {
-            return DefaultOrganisation.castOrCopy((Organisation) object);
-        }
-        if (object == null || object instanceof AbstractParty) {
-            return (AbstractParty) object;
-        }
-        return new AbstractParty(object);
-    }
-
-    /**
      * Return the name of the party.
      *
      * @return Name of the party.
      */
-    @Override
     @XmlElement(name = "name")
+    @UML(identifier="name", obligation=CONDITIONAL, specification=ISO_19115)
     public InternationalString getName() {
         return name;
     }
@@ -168,8 +143,8 @@
      *
      * @return Contact information for the party.
      */
-    @Override
     @XmlElement(name = "contactInfo")
+    @UML(identifier="contactInfo", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Contact> getContactInfo() {
         return contactInfo = nonNullCollection(contactInfo, Contact.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 925eb89..f16d57d 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 2ea3268..f79b217 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
@@ -21,12 +21,13 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 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;
@@ -36,6 +37,8 @@
 import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.xml.IdentifierMap;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
@@ -86,7 +89,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.
@@ -119,7 +122,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.
@@ -136,7 +139,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
@@ -183,7 +186,6 @@
      *
      * @see #castOrCopy(Citation)
      */
-    @SuppressWarnings("deprecation")
     public DefaultCitation(final Citation object) {
         super(object);
         if (object != null) {
@@ -193,13 +195,16 @@
             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);
+            if (object instanceof DefaultCitation) {
+                final DefaultCitation c = (DefaultCitation) object;
+                onlineResources = copyCollection(c.getOnlineResources(), OnlineResource.class);
+                graphics        = copyCollection(c.getGraphics(), BrowseGraphic.class);
+            }
             final String id1        = object.getISBN();
             final String id2        = object.getISSN();
             if (id1 != null || id2 != null) {
@@ -389,22 +394,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 {@link 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 {@link 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);
     }
 
     /**
@@ -451,21 +466,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 = newValue;
     }
 
     /**
@@ -581,8 +607,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "onlineResource")
+    @UML(identifier="onlineResource", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<OnlineResource> getOnlineResources() {
         return onlineResources = nonNullCollection(onlineResources, OnlineResource.class);
     }
@@ -605,8 +631,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "graphic")
+    @UML(identifier="graphic", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<BrowseGraphic> getGraphics() {
         return graphics = nonNullCollection(graphics, BrowseGraphic.class);
     }
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 72f604a..8d61ec4 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
@@ -22,16 +22,21 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.opengis.annotation.UML;
+import org.opengis.util.CodeList;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Address;
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.Telephone;
 import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.citation.TelephoneType;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.resources.Messages;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
+
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 
 
 /**
@@ -86,7 +91,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.
@@ -126,12 +131,19 @@
     public DefaultContact(final Contact object) {
         super(object);
         if (object != null) {
-            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();
+            if (object instanceof DefaultContact) {
+                final DefaultContact c = (DefaultContact) object;
+                phones          = copyCollection(c.getPhones(), Telephone.class);
+                addresses       = copyCollection(c.getAddresses(), Address.class);
+                onlineResources = copyCollection(c.getOnlineResources(), OnlineResource.class);
+                contactType     = c.getContactType();
+            } else {
+                phones          = singleton(object.getPhone(), Telephone.class);
+                addresses       = singleton(object.getAddress(), Address.class);
+                onlineResources = singleton(object.getOnlineResource(), OnlineResource.class);
+            }
         }
     }
 
@@ -167,7 +179,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="phone", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Telephone> getPhones() {
         return phones = nonNullCollection(phones, Telephone.class);
     }
@@ -220,20 +232,23 @@
         Telephone phone = null;
         final Collection<Telephone> phones = getPhones();
         if (phones != null) { // May be null on marshalling.
-            TelephoneType ignored = null;
+            CodeList<?> ignored = null;
             for (final Telephone c : phones) {
-                final TelephoneType type = c.getNumberType();
-                if (TelephoneType.VOICE.equals(type) || TelephoneType.FACSIMILE.equals(type)) {
-                    if (phone == null) {
-                        phone = c;
+                if (c instanceof DefaultTelephone) {
+                    String name;
+                    final CodeList<?> type = ((DefaultTelephone) c).numberType;
+                    if (type != null && ("VOICE".equals(name = type.name()) || "FACSIMILE".equals(name))) {
+                        if (phone == null) {
+                            phone = c;
+                        }
+                    } else if (ignored == null) {
+                        ignored = type;
                     }
-                } else if (ignored == null) {
-                    ignored = type;
                 }
             }
             if (ignored != null) {
                 Context.warningOccured(Context.current(), DefaultContact.class, "getPhone",
-                        Messages.class, Messages.Keys.IgnoredPropertyAssociatedTo_1, ignored.toString());
+                        Messages.class, Messages.Keys.IgnoredPropertyAssociatedTo_1, ignored);
             }
         }
         return phone;
@@ -256,10 +271,10 @@
             } else {
                 newValues = new ArrayList<Telephone>(4);
                 for (String number : newValue.getVoices()) {
-                    newValues.add(new DefaultTelephone(number, TelephoneType.VOICE));
+                    newValues.add(new DefaultTelephone(number, UnsupportedCodeList.VOICE));
                 }
                 for (String number : newValue.getFacsimiles()) {
-                    newValues.add(new DefaultTelephone(number, TelephoneType.FACSIMILE));
+                    newValues.add(new DefaultTelephone(number, UnsupportedCodeList.FACSIMILE));
                 }
             }
         }
@@ -273,7 +288,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="address", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Address> getAddresses() {
         return addresses = nonNullCollection(addresses, Address.class);
     }
@@ -324,7 +339,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="onlineResource", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<OnlineResource> getOnlineResources() {
         return onlineResources = nonNullCollection(onlineResources, OnlineResource.class);
     }
@@ -371,21 +386,32 @@
     /**
      * Returns the time period (including time zone) when individuals can contact the organization or individual.
      *
-     * @return Time period 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, or {@code null}.
      */
     @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, or {@code null} if none.
      */
-    public void setHoursOfService(final Collection<? extends InternationalString> newValues) {
-        hoursOfService = writeCollection(newValues, hoursOfService, InternationalString.class);
+    public void setHoursOfService(final InternationalString newValue) {
+        checkWritePermission();
+        hoursOfService = newValue;
     }
 
     /**
@@ -417,8 +443,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "contactType")
+    @UML(identifier="contactType", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getContactType() {
         return contactType;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
index 55462b0..f99a2a9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
@@ -20,14 +20,26 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.citation.Contact;
-import org.opengis.metadata.citation.Individual;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.Types;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the party if the party is an individual.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code Individual} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -47,7 +59,8 @@
     "positionName"
 })
 @XmlRootElement(name = "CI_Individual")
-public class DefaultIndividual extends AbstractParty implements Individual {
+@UML(identifier="CI_Individual", specification=ISO_19115)
+public class DefaultIndividual extends AbstractParty {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -85,10 +98,8 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(Individual)
      */
-    public DefaultIndividual(final Individual object) {
+    public DefaultIndividual(final DefaultIndividual object) {
         super(object);
         if (object != null) {
             positionName = object.getPositionName();
@@ -96,37 +107,12 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultIndividual}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultIndividual} instance is created using the
-     *       {@linkplain #DefaultIndividual(Individual) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultIndividual castOrCopy(final Individual object) {
-        if (object == null || object instanceof DefaultIndividual) {
-            return (DefaultIndividual) object;
-        }
-        return new DefaultIndividual(object);
-    }
-
-    /**
      * Returns position of the individual in an organization, or {@code null} if none.
      *
      * @return Position of the individual in an organization, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "positionName")
+    @UML(identifier="positionName", obligation=CONDITIONAL, specification=ISO_19115)
     public InternationalString getPositionName() {
         return positionName;
     }
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 d77d4ec..138d9c0 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
@@ -20,11 +20,15 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.citation.OnlineResource;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about on-line sources from which the dataset, specification, or
@@ -80,7 +84,7 @@
     /**
      * Name of the online resources.
      */
-    private InternationalString name;
+    private String name;
 
     /**
      * Detailed text description of what the online resource is/does.
@@ -132,7 +136,9 @@
             name               = object.getName();
             description        = object.getDescription();
             function           = object.getFunction();
-            protocolRequest    = object.getProtocolRequest();
+            if (object instanceof DefaultOnlineResource) {
+                protocolRequest = ((DefaultOnlineResource) object).getProtocolRequest();
+            }
         }
     }
 
@@ -186,20 +192,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 = newValue;
     }
@@ -312,7 +326,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="protocolRequest", obligation=OPTIONAL, specification=ISO_19115)
     public String getProtocolRequest() {
         return protocolRequest;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOrganisation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOrganisation.java
index 4a7e3fe..1a05a5e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOrganisation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOrganisation.java
@@ -21,14 +21,26 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.citation.Contact;
-import org.opengis.metadata.citation.Individual;
-import org.opengis.metadata.citation.Organisation;
 import org.opengis.metadata.identification.BrowseGraphic;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the party if the party is an organization.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code Organisation} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -49,7 +61,8 @@
     "individual"
 })
 @XmlRootElement(name = "CI_Organisation")
-public class DefaultOrganisation extends AbstractParty implements Organisation {
+@UML(identifier="CI_Organisation", specification=ISO_19115)
+public class DefaultOrganisation extends AbstractParty {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -63,7 +76,7 @@
     /**
      * Individuals in the named organization.
      */
-    private Collection<Individual> individual;
+    private Collection<DefaultIndividual> individual;
 
     /**
      * Constructs an initially empty organization.
@@ -81,12 +94,12 @@
      */
     public DefaultOrganisation(final CharSequence name,
                                final BrowseGraphic logo,
-                               final Individual individual,
+                               final DefaultIndividual individual,
                                final Contact contactInfo)
     {
         super(name, contactInfo);
         this.logo       = singleton(logo, BrowseGraphic.class);
-        this.individual = singleton(individual, Individual.class);
+        this.individual = singleton(individual, DefaultIndividual.class);
     }
 
     /**
@@ -95,49 +108,22 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(Organisation)
      */
-    public DefaultOrganisation(final Organisation object) {
+    public DefaultOrganisation(final DefaultOrganisation object) {
         super(object);
         if (object != null) {
             logo       = copyCollection(object.getLogo(), BrowseGraphic.class);
-            individual = copyCollection(object.getIndividual(), Individual.class);
+            individual = copyCollection(object.getIndividual(), DefaultIndividual.class);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultOrganisation}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultOrganisation} instance is created using the
-     *       {@linkplain #DefaultOrganisation(Organisation) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultOrganisation castOrCopy(final Organisation object) {
-        if (object == null || object instanceof DefaultOrganisation) {
-            return (DefaultOrganisation) object;
-        }
-        return new DefaultOrganisation(object);
-    }
-
-    /**
      * Returns the graphics identifying organization.
      *
      * @return Graphics identifying organization, or an empty collection if there is none.
      */
-    @Override
     @XmlElement(name = "logo")
+    @UML(identifier="logo", obligation=CONDITIONAL, specification=ISO_19115)
     public Collection<BrowseGraphic> getLogo() {
         return logo = nonNullCollection(logo, BrowseGraphic.class);
     }
@@ -154,20 +140,30 @@
     /**
      * Returns the individuals in the named organization.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Individual} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Individuals in the named organization, or an empty collection.
      */
-    @Override
     @XmlElement(name = "individual")
-    public Collection<Individual> getIndividual() {
-        return individual = nonNullCollection(individual, Individual.class);
+    @UML(identifier="individual", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultIndividual> getIndividual() {
+        return individual = nonNullCollection(individual, DefaultIndividual.class);
     }
 
     /**
      * Sets the individuals in the named organization.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Individual} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new individuals in the named organization.
      */
-    public void setIndividual(final Collection<? extends Individual> newValues) {
-        individual = writeCollection(newValues, individual, Individual.class);
+    public void setIndividual(final Collection<? extends DefaultIndividual> newValues) {
+        individual = writeCollection(newValues, individual, DefaultIndividual.class);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
index 97c811a..78e37ff 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
@@ -21,16 +21,29 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
-import org.opengis.metadata.citation.Party;
-import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.citation.ResponsibleParty;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the party and their role.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code Responsibility} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -55,7 +68,8 @@
 @XmlSeeAlso({
     DefaultResponsibleParty.class
 })
-public class DefaultResponsibility extends ISOMetadata implements Responsibility {
+@UML(identifier="CI_Responsibility", specification=ISO_19115)
+public class DefaultResponsibility extends ISOMetadata {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -74,7 +88,7 @@
     /**
      * Information about the parties.
      */
-    private Collection<Party> parties;
+    private Collection<AbstractParty> parties;
 
     /**
      * Constructs an initially empty responsible party.
@@ -89,10 +103,10 @@
      * @param extent Spatial or temporal extent of the role, or {@code null}.
      * @param party  Information about the party, or {@code null}.
      */
-    public DefaultResponsibility(final Role role, final Extent extent, final Party party) {
+    public DefaultResponsibility(final Role role, final Extent extent, final AbstractParty party) {
         this.role    = role;
         this.extents = singleton(extent, Extent.class);
-        this.parties = singleton(party, Party.class);
+        this.parties = singleton(party, AbstractParty.class);
     }
 
     /**
@@ -101,41 +115,29 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(Responsibility)
      */
-    public DefaultResponsibility(final Responsibility object) {
+    public DefaultResponsibility(final DefaultResponsibility object) {
         super(object);
         if (object != null) {
             this.role    = object.getRole();
             this.extents = copyCollection(object.getExtents(), Extent.class);
-            this.parties = copyCollection(object.getParties(), Party.class);
+            this.parties = copyCollection(object.getParties(), AbstractParty.class);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultResponsibility}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultResponsibility} instance is created using the
-     *       {@linkplain #DefaultResponsibility(Responsibility) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       Responsibility contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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.
+     * Bridge constructor for {@link DefaultResponsibleParty#DefaultResponsibleParty(ResponsibleParty)}.
      */
-    public static DefaultResponsibility castOrCopy(final Responsibility object) {
-        if (object == null || object instanceof DefaultResponsibility) {
-            return (DefaultResponsibility) object;
+    DefaultResponsibility(final ResponsibleParty object) {
+        super(object);
+        if (object != null) {
+            this.role = object.getRole();
+            if (object instanceof DefaultResponsibility) {
+                final DefaultResponsibility c = (DefaultResponsibility) object;
+                this.extents = copyCollection(c.getExtents(), Extent.class);
+                this.parties = copyCollection(c.getParties(), AbstractParty.class);
+            }
         }
-        return new DefaultResponsibility(object);
     }
 
     /**
@@ -143,8 +145,8 @@
      *
      * @return Function performed by the responsible party.
      */
-    @Override
 /// @XmlElement(name = "role", required = true)
+    @UML(identifier="role", obligation=MANDATORY, specification=ISO_19115)
     public Role getRole() {
         return role;
     }
@@ -164,8 +166,8 @@
      *
      * @return The spatial or temporal extents of the role.
      */
-    @Override
 /// @XmlElement(name = "extent")
+    @UML(identifier="extent", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Extent> getExtents() {
         return extents = nonNullCollection(extents, Extent.class);
     }
@@ -182,20 +184,30 @@
     /**
      * Returns information about the parties.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Party} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information about the parties.
      */
-    @Override
 /// @XmlElement(name = "party", required = true)
-    public Collection<Party> getParties() {
-        return parties = nonNullCollection(parties, Party.class);
+    @UML(identifier="party", obligation=MANDATORY, specification=ISO_19115)
+    public Collection<AbstractParty> getParties() {
+        return parties = nonNullCollection(parties, AbstractParty.class);
     }
 
     /**
      * Sets information about the parties.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Party} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues New information about the parties.
      */
-    public void setParties(final Collection<? extends Party> newValues) {
-        parties = writeCollection(newValues, parties, Party.class);
+    public void setParties(final Collection<? extends AbstractParty> newValues) {
+        parties = writeCollection(newValues, parties, AbstractParty.class);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
index ed43206..38e4690 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
@@ -23,10 +23,6 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.citation.Contact;
-import org.opengis.metadata.citation.Party;
-import org.opengis.metadata.citation.Individual;
-import org.opengis.metadata.citation.Organisation;
-import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Role;
 import org.opengis.util.InternationalString;
@@ -38,8 +34,11 @@
  * Identification of, and means of communication with, person(s) and
  * organizations associated with the dataset.
  *
- * @deprecated As of ISO 19115:2014, the {@code ResponsibleParty} type has been replaced by {@code Responsibility}
- *             to allow more flexible associations of individuals, organizations, and roles.
+ * <div class="warning"><b>Upcoming API change — deprecation</b><br>
+ * As of ISO 19115:2014, the {@code ResponsibleParty} type has been replaced by {@code Responsibility}
+ * to allow more flexible associations of individuals, organisations, and roles.
+ * This {@code ResponsibleParty} interface may be deprecated in GeoAPI 4.0.
+ * </div>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
@@ -48,7 +47,6 @@
  * @version 0.5
  * @module
  */
-@Deprecated
 @XmlType(name = "CI_ResponsibleParty_Type", propOrder = {
     "individualName",
     "organisationName",
@@ -84,14 +82,29 @@
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(Responsibility)
      */
-    public DefaultResponsibleParty(final Responsibility object) {
+    public DefaultResponsibleParty(final DefaultResponsibility object) {
         super(object);
     }
 
     /**
+     * Constructs a new instance initialized with the values from the specified metadata object.
+     * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
+     * given object are not recursively copied.
+     *
+     * @param object The metadata to copy values from, or {@code null} if none.
+     *
+     * @see #castOrCopy(ResponsibleParty)
+     */
+    public DefaultResponsibleParty(final ResponsibleParty object) {
+        super(object);
+        if (object != null && !(object instanceof DefaultResponsibility)) {
+            setIndividualName(object.getIndividualName());
+            setOrganisationName(object.getOrganisationName());
+        }
+    }
+
+    /**
      * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
      * This method performs the first applicable action in the following choices:
      *
@@ -100,7 +113,7 @@
      *   <li>Otherwise if the given object is already an instance of
      *       {@code DefaultResponsibleParty}, then it is returned unchanged.</li>
      *   <li>Otherwise a new {@code DefaultResponsibleParty} instance is created using the
-     *       {@linkplain #DefaultResponsibleParty(Responsibility) copy constructor}
+     *       {@linkplain #DefaultResponsibleParty(ResponsibleParty) copy constructor}
      *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
      *       metadata contained in the given object are not recursively copied.</li>
      * </ul>
@@ -109,7 +122,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 DefaultResponsibleParty castOrCopy(final Responsibility object) {
+    public static DefaultResponsibleParty castOrCopy(final ResponsibleParty object) {
         if (object == null || object instanceof DefaultResponsibleParty) {
             return (DefaultResponsibleParty) object;
         }
@@ -128,12 +141,12 @@
      * @see #getPositionName()
      */
     private InternationalString getIndividual(final boolean position) {
-        final Collection<Party> parties = getParties();
-        InternationalString name = getName(parties, Individual.class, position);
+        final Collection<AbstractParty> parties = getParties();
+        InternationalString name = getName(parties, DefaultIndividual.class, position);
         if (name == null && parties != null) {
-            for (final Party party : parties) {
-                if (party instanceof Organisation) {
-                    name = getName(((Organisation) party).getIndividual(), Individual.class, position);
+            for (final AbstractParty party : parties) {
+                if (party instanceof DefaultOrganisation) {
+                    name = getName(((DefaultOrganisation) party).getIndividual(), DefaultIndividual.class, position);
                     if (name != null) {
                         break;
                     }
@@ -153,20 +166,20 @@
      * @see #getIndividualName()
      * @see #getPositionName()
      */
-    private static InternationalString getName(final Collection<? extends Party> parties,
-            final Class<? extends Party> type, final boolean position)
+    private static InternationalString getName(final Collection<? extends AbstractParty> parties,
+            final Class<? extends AbstractParty> type, final boolean position)
     {
         InternationalString name = null;
         if (parties != null) { // May be null on marshalling.
-            for (final Party party : parties) {
+            for (final AbstractParty party : parties) {
                 if (type.isInstance(party)) {
                     if (name != null) {
                         LegacyPropertyAdapter.warnIgnoredExtraneous(type, DefaultResponsibleParty.class,
-                                position ? "getPositionName" : (type == Individual.class)
+                                position ? "getPositionName" : (type == DefaultIndividual.class)
                                          ? "getIndividualName" : "getOrganisationName");
                         break;
                     }
-                    name = position ? ((Individual) party).getPositionName() : party.getName();
+                    name = position ? ((DefaultIndividual) party).getPositionName() : party.getName();
                 }
             }
         }
@@ -178,18 +191,18 @@
      *
      * @return {@code true} if the name has been set, or {@code false} otherwise.
      */
-    private boolean setName(final Class<? extends Party> type, final boolean position, final InternationalString name) {
+    private boolean setName(final Class<? extends AbstractParty> type, final boolean position, final InternationalString name) {
         checkWritePermission();
-        final Iterator<Party> it = getParties().iterator();
+        final Iterator<AbstractParty> it = getParties().iterator();
         while (it.hasNext()) {
-            final Party party = it.next();
-            if (party instanceof AbstractParty && type.isInstance(party)) {
+            final AbstractParty party = it.next();
+            if (type.isInstance(party)) {
                 if (position) {
                     ((DefaultIndividual) party).setPositionName(name);
                 } else {
-                    ((AbstractParty) party).setName(name);
+                    party.setName(name);
                 }
-                if (((AbstractParty) party).isEmpty()) {
+                if (party.isEmpty()) {
                     it.remove();
                 }
                 return true;
@@ -233,7 +246,7 @@
      */
     @Deprecated
     public void setIndividualName(final String newValue) {
-        if (!setName(Individual.class, false, Types.toInternationalString(newValue))) {
+        if (!setName(DefaultIndividual.class, false, Types.toInternationalString(newValue))) {
             getParties().add(new DefaultIndividual(newValue, null, null));
         }
     }
@@ -254,7 +267,7 @@
     @Deprecated
     @XmlElement(name = "organisationName")
     public InternationalString getOrganisationName() {
-        return getName(getParties(), Organisation.class, false);
+        return getName(getParties(), DefaultOrganisation.class, false);
     }
 
     /**
@@ -271,7 +284,7 @@
      */
     @Deprecated
     public void setOrganisationName(final InternationalString newValue) {
-        if (!setName(Organisation.class, false, Types.toInternationalString(newValue))) {
+        if (!setName(DefaultOrganisation.class, false, Types.toInternationalString(newValue))) {
             getParties().add(new DefaultOrganisation(newValue, null, null, null));
         }
     }
@@ -329,9 +342,9 @@
     @Deprecated
     @XmlElement(name = "contactInfo")
     public Contact getContactInfo() {
-        final Collection<Party> parties = getParties();
+        final Collection<AbstractParty> parties = getParties();
         if (parties != null) { // May be null on marshalling.
-            for (final Party party : parties) {
+            for (final AbstractParty party : parties) {
                 final Collection<? extends Contact> contacts = party.getContactInfo();
                 if (contacts != null) { // May be null on marshalling.
                     for (final Contact contact : contacts) {
@@ -358,16 +371,14 @@
     @Deprecated
     public void setContactInfo(final Contact newValue) {
         checkWritePermission();
-        final Iterator<Party> it = getParties().iterator();
+        final Iterator<AbstractParty> it = getParties().iterator();
         while (it.hasNext()) {
-            final Party party = it.next();
-            if (party instanceof AbstractParty) {
-                ((AbstractParty) party).setContactInfo(newValue != null ? Collections.singleton(newValue) : null);
-                if (((AbstractParty) party).isEmpty()) {
-                    it.remove();
-                }
-                return;
+            final AbstractParty party = it.next();
+            party.setContactInfo(newValue != null ? Collections.singleton(newValue) : null);
+            if (party.isEmpty()) {
+                it.remove();
             }
+            return;
         }
         /*
          * If no existing AbstractParty were found, add a new one. However there is no way to know if
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 f45094b..0f097ff 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
@@ -40,7 +40,7 @@
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
 @XmlType(name = "CI_Series_Type", propOrder = {
@@ -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 = 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 = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
index 7b7108c..2f8fae3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
@@ -22,11 +22,17 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.util.CodeList;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.citation.Telephone;
-import org.opengis.metadata.citation.TelephoneType;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Telephone numbers for contacting the responsible individual or organization.
@@ -81,7 +87,7 @@
     /**
      * Type of telephone number.
      */
-    private TelephoneType numberType;
+    CodeList<?> numberType;
 
     /**
      * Constructs a default telephone.
@@ -97,7 +103,7 @@
      *
      * @since 0.5
      */
-    public DefaultTelephone(final String number, final TelephoneType numberType) {
+    DefaultTelephone(final String number, final CodeList<?> numberType) {
         this.number     = number;
         this.numberType = numberType;
     }
@@ -114,8 +120,13 @@
     public DefaultTelephone(final Telephone object) {
         super(object);
         if (object != null) {
-            number     = object.getNumber();
-            numberType = object.getNumberType();
+            if (object instanceof DefaultTelephone) {
+                number     = ((DefaultTelephone) object).getNumber();
+                numberType = ((DefaultTelephone) object).numberType;
+            } else {
+                setVoices(object.getVoices());
+                setFacsimiles(object.getFacsimiles());
+            }
         }
     }
 
@@ -151,8 +162,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "number", required = true)
+    @UML(identifier="number", obligation=MANDATORY, specification=ISO_19115)
     public String getNumber() {
         return number;
     }
@@ -171,25 +182,61 @@
 
     /**
      * Returns the type of telephone number, or {@code null} if none.
+     * If non-null, the type can be {@code "VOICE"}, {@code "FACSIMILE"} or {@code "SMS"}.
+     *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The return type will be changed to the {@code TelephoneType} code list
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
      *
      * @return Type of telephone number, or {@code null} if none.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "numberType")
-    public TelephoneType getNumberType() {
+    @UML(identifier="numberType", obligation=OPTIONAL, specification=ISO_19115)
+    public CodeList<?> getNumberType() {
         return numberType;
     }
 
     /**
      * Sets the type of telephone number.
+     * If non-null, the type can only be {@code "VOICE"}, {@code "FACSIMILE"} or {@code "SMS"}.
+     *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The argument type will be changed to the {@code TelephoneType} code list when GeoAPI will provide it
+     * (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
+     *
+     * {@preformat java
+     *   final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+     *       private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+     *
+     *       // Need to declare at least one code list element.
+     *       public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
+     *
+     *       private UnsupportedCodeList(String name) {
+     *           super(name, VALUES);
+     *       }
+     *
+     *       public static UnsupportedCodeList valueOf(String code) {
+     *           return valueOf(UnsupportedCodeList.class, code);
+     *       }
+     *
+     *       &#64;Override
+     *       public UnsupportedCodeList[] family() {
+     *           synchronized (VALUES) {
+     *               return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+     *           }
+     *       }
+     *   }
+     * }
+     * </div>
      *
      * @param newValue The new type of telephone number.
      *
      * @since 0.5
      */
-    public void setNumberType(final TelephoneType newValue) {
+    public void setNumberType(final CodeList<?> newValue) {
         checkWritePermission();
         numberType = newValue;
     }
@@ -263,7 +310,7 @@
     @Deprecated
     @XmlElement(name = "voice")
     public final Collection<String> getVoices() {
-        return new LegacyTelephones(getOwner(), TelephoneType.VOICE);
+        return new LegacyTelephones(getOwner(), UnsupportedCodeList.VOICE);
     }
 
     /**
@@ -295,7 +342,7 @@
     @Deprecated
     @XmlElement(name = "facsimile")
     public final Collection<String> getFacsimiles() {
-        return new LegacyTelephones(getOwner(), TelephoneType.FACSIMILE);
+        return new LegacyTelephones(getOwner(), UnsupportedCodeList.FACSIMILE);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java
index a3420b9..4f00490 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/LegacyTelephones.java
@@ -18,8 +18,8 @@
 
 import java.util.Collection;
 import java.util.Iterator;
+import org.opengis.util.CodeList;
 import org.opengis.metadata.citation.Telephone;
-import org.opengis.metadata.citation.TelephoneType;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
 
@@ -36,14 +36,14 @@
 final class LegacyTelephones extends LegacyPropertyAdapter<String,Telephone> {
     /**
      * The type of telephone number.
-     * Either {@link TelephoneType#VOICE} or {@link TelephoneType#FACSIMILE}.
+     * Either {@link UnsupportedCodeList#VOICE} or {@link UnsupportedCodeList#FACSIMILE}.
      */
-    private final TelephoneType type;
+    private final CodeList<?> type;
 
     /**
      * Wraps the given telephone list for the given type.
      */
-    LegacyTelephones(final Collection<Telephone> telephones, final TelephoneType type) {
+    LegacyTelephones(final Collection<Telephone> telephones, final CodeList<?> type) {
         super(telephones);
         this.type = type;
     }
@@ -61,8 +61,13 @@
      */
     @Override
     protected String unwrap(final Telephone container) {
-        if (container != null && type.equals(container.getNumberType())) {
-            return container.getNumber();
+        if (container instanceof DefaultTelephone) {
+            final CodeList<?> ct = ((DefaultTelephone) container).numberType;
+            if (ct != null) {
+                if (type.name().equals(ct.name())) {
+                    return ((DefaultTelephone) container).getNumber();
+                }
+            }
         }
         return null;
     }
@@ -73,10 +78,10 @@
     @Override
     protected boolean update(final Telephone container, final String value) {
         if (container instanceof DefaultTelephone) {
-            final TelephoneType ct = container.getNumberType();
-            if (ct == null || ct.equals(type)) {
+            final CodeList<?> ct = ((DefaultTelephone) container).numberType;
+            if (ct == null || type.name().equals(ct.name())) {
                 if (ct == null) {
-                    ((DefaultTelephone) container).setNumberType(type);
+                    ((DefaultTelephone) container).numberType = type;
                 }
                 ((DefaultTelephone) container).setNumber(value);
                 return true;
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 8fbef3a..3b693d8 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
@@ -105,7 +105,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/constraint/DefaultConstraints.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
index ef0d63b..f70d63b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
@@ -21,18 +21,21 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.constraint.Releasability;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.constraint.LegalConstraints;
 import org.opengis.metadata.constraint.SecurityConstraints;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Restrictions on the access and use of a resource or metadata.
@@ -97,12 +100,12 @@
     /**
      * Citation for the limitation of constraint.
      */
-    private Releasability releasability;
+    private DefaultReleasability releasability;
 
     /**
      * Party responsible for the resource constraints.
      */
-    private Collection<Responsibility> responsibleParties;
+    private Collection<DefaultResponsibility> responsibleParties;
 
     /**
      * Constructs an initially empty constraints.
@@ -132,11 +135,14 @@
         super(object);
         if (object != null) {
             useLimitations             = copyCollection(object.getUseLimitations(), InternationalString.class);
-            constraintApplicationScope = object.getConstraintApplicationScope();
-            graphics                   = copyCollection(object.getGraphics(), BrowseGraphic.class);
-            references                 = copyCollection(object.getReferences(), Citation.class);
-            releasability              = object.getReleasability();
-            responsibleParties         = copyCollection(object.getResponsibleParties(), Responsibility.class);
+            if (object instanceof DefaultConstraints) {
+                final DefaultConstraints c = (DefaultConstraints) object;
+                constraintApplicationScope = c.getConstraintApplicationScope();
+                graphics                   = copyCollection(c.getGraphics(), BrowseGraphic.class);
+                references                 = copyCollection(c.getReferences(), Citation.class);
+                releasability              = c.getReleasability();
+                responsibleParties         = copyCollection(c.getResponsibleParties(), DefaultResponsibility.class);
+            }
         }
     }
 
@@ -207,8 +213,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "constraintApplicationScope")
+    @UML(identifier="constraintApplicationScope", obligation=OPTIONAL, specification=ISO_19115)
     public Scope getConstraintApplicationScope() {
         return constraintApplicationScope;
     }
@@ -232,8 +238,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "graphic")
+    @UML(identifier="graphic", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<BrowseGraphic> getGraphics() {
         return graphics = nonNullCollection(graphics, BrowseGraphic.class);
     }
@@ -257,8 +263,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "reference")
+    @UML(identifier="reference", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getReferences() {
         return references = nonNullCollection(references, Citation.class);
     }
@@ -277,24 +283,34 @@
     /**
      * Returns information concerning the parties to whom the resource can or cannot be released.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The return type will be changed to the {@code Releasability} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information concerning the parties to whom the resource, or {@code null} if none.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "releasability")
-    public Releasability getReleasability() {
+    @UML(identifier="releasability", obligation=OPTIONAL, specification=ISO_19115)
+    public DefaultReleasability getReleasability() {
         return releasability;
     }
 
     /**
      * Sets the information concerning the parties to whom the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The argument type will be changed to the {@code Releasability} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValue The new information concerning the parties to whom the resource.
      *
      * @since 0.5
      */
-    public void setReleasability(final Releasability newValue) {
+    public void setReleasability(final DefaultReleasability newValue) {
         checkWritePermission();
         releasability = newValue;
     }
@@ -302,24 +318,34 @@
     /**
      * Returns the parties responsible for the resource constraints.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Responsibility} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Parties responsible for the resource constraints.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "responsibleParty")
-    public Collection<Responsibility> getResponsibleParties() {
-        return responsibleParties = nonNullCollection(responsibleParties, Responsibility.class);
+    @UML(identifier="responsibleParty", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultResponsibility> getResponsibleParties() {
+        return responsibleParties = nonNullCollection(responsibleParties, DefaultResponsibility.class);
     }
 
     /**
      * Sets the parties responsible for the resource constraints.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Responsibility} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new parties responsible for the resource constraints.
      *
      * @since 0.5
      */
-    public void setResponsibleParties(final Collection<? extends Responsibility> newValues) {
-        responsibleParties = writeCollection(newValues, responsibleParties, Responsibility.class);
+    public void setResponsibleParties(final Collection<? extends DefaultResponsibility> newValues) {
+        responsibleParties = writeCollection(newValues, responsibleParties, DefaultResponsibility.class);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
index deb26ac..0873f02 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
@@ -21,15 +21,27 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.constraint.Releasability;
 import org.opengis.metadata.constraint.Restriction;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
+
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 
 
 /**
  * Information about resource release constraints.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code Releasability} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -50,7 +62,8 @@
     "disseminationConstraints"
 })
 @XmlRootElement(name = "MD_Releasability")
-public class DefaultReleasability extends ISOMetadata implements Releasability {
+@UML(identifier="MD_Releasability", specification=ISO_19115)
+public class DefaultReleasability extends ISOMetadata {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -59,7 +72,7 @@
     /**
      * Party to which the release statement applies.
      */
-    private Collection<Responsibility> addressees;
+    private Collection<DefaultResponsibility> addressees;
 
     /**
      * Release statement.
@@ -86,58 +99,43 @@
      *
      * @see #castOrCopy(Releasability)
      */
-    public DefaultReleasability(final Releasability object) {
+    public DefaultReleasability(final DefaultReleasability object) {
         super(object);
         if (object != null) {
-            addressees                = copyCollection(object.getAddressees(), Responsibility.class);
+            addressees                = copyCollection(object.getAddressees(), DefaultResponsibility.class);
             statement                 = object.getStatement();
             disseminationConstraints  = copyCollection(object.getDisseminationConstraints(), Restriction.class);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultReleasability}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultReleasability} instance is created using the
-     *       {@linkplain #DefaultReleasability(Releasability) copy constructor} and returned.
-     *       Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultReleasability castOrCopy(final Releasability object) {
-        if (object == null || object instanceof DefaultReleasability) {
-            return (DefaultReleasability) object;
-        }
-        return new DefaultReleasability(object);
-    }
-
-    /**
      * Returns the parties to which the release statement applies.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Responsibility} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Parties to which the release statement applies.
      */
-    @Override
     @XmlElement(name = "addressee")
-    public Collection<Responsibility> getAddressees() {
-        return addressees = nonNullCollection(addressees, Responsibility.class);
+    @UML(identifier="addressee", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultResponsibility> getAddressees() {
+        return addressees = nonNullCollection(addressees, DefaultResponsibility.class);
     }
 
     /**
      * Sets the parties to which the release statement applies.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code Responsibility} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new parties.
      */
-    public void getAddressees(final Collection<? extends Responsibility> newValues) {
-        addressees = writeCollection(newValues, addressees, Responsibility.class);
+    public void getAddressees(final Collection<? extends DefaultResponsibility> newValues) {
+        addressees = writeCollection(newValues, addressees, DefaultResponsibility.class);
     }
 
     /**
@@ -145,8 +143,8 @@
      *
      * @return Release statement, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "statement")
+    @UML(identifier="statement", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getStatement() {
         return statement;
     }
@@ -166,8 +164,8 @@
      *
      * @return Components in determining releasability.
      */
-    @Override
     @XmlElement(name = "disseminationConstraints")
+    @UML(identifier="disseminationConstraints", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Restriction> getDisseminationConstraints() {
         return disseminationConstraints = nonNullCollection(disseminationConstraints, Restriction.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultAttributeGroup.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultAttributeGroup.java
index 32833fd..7900c98 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultAttributeGroup.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultAttributeGroup.java
@@ -20,16 +20,29 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.opengis.metadata.content.AttributeGroup;
 import org.opengis.metadata.content.CoverageContentType;
 import org.opengis.metadata.content.RangeDimension;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about content type for groups of attributes for a specific
  * {@linkplain DefaultRangeDimension range dimension}.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code AttributeGroup} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -50,7 +63,8 @@
     "attribute"
 })
 @XmlRootElement(name = "MD_AttributeGroup")
-public class DefaultAttributeGroup extends ISOMetadata implements AttributeGroup {
+@UML(identifier="MD_AttributeGroup", specification=ISO_19115)
+public class DefaultAttributeGroup extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -92,7 +106,7 @@
      *
      * @see #castOrCopy(AttributeGroup)
      */
-    public DefaultAttributeGroup(final AttributeGroup object) {
+    public DefaultAttributeGroup(final DefaultAttributeGroup object) {
         super(object);
         if (object != null) {
             contentTypes = copyCollection(object.getContentTypes(), CoverageContentType.class);
@@ -101,37 +115,12 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultAttributeGroup}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultAttributeGroup} instance is created using the
-     *       {@linkplain #DefaultAttributeGroup(AttributeGroup) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultAttributeGroup castOrCopy(final AttributeGroup object) {
-        if (object == null || object instanceof DefaultAttributeGroup) {
-            return (DefaultAttributeGroup) object;
-        }
-        return new DefaultAttributeGroup(object);
-    }
-
-    /**
      * Returns the types of information represented by the value(s).
      *
      * @return The types of information represented by the value(s).
      */
-    @Override
     @XmlElement(name = "contentType", required = true)
+    @UML(identifier="contentType", obligation=MANDATORY, specification=ISO_19115)
     public Collection<CoverageContentType> getContentTypes() {
         return contentTypes = nonNullCollection(contentTypes, CoverageContentType.class);
     }
@@ -150,8 +139,8 @@
      *
      * @return Information on an attribute of the resource.
      */
-    @Override
     @XmlElement(name = "attribute")
+    @UML(identifier="attribute", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<RangeDimension> getAttributes() {
         return attributes = nonNullCollection(attributes, RangeDimension.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 e387b82..c780238 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
@@ -22,6 +22,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.content.Band;
 import org.opengis.metadata.content.BandDefinition;
 import org.opengis.metadata.content.PolarizationOrientation;
@@ -31,6 +32,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Range of wavelengths in the electromagnetic spectrum.
@@ -137,9 +142,12 @@
     public DefaultBand(final Band object) {
         super(object);
         if (object != null) {
-            boundMin                 = object.getBoundMin();
-            boundMax                 = object.getBoundMax();
-            boundUnits               = object.getBoundUnits();
+            if (object instanceof DefaultBand) {
+                final DefaultBand c = (DefaultBand) object;
+                boundMin   = c.getBoundMin();
+                boundMax   = c.getBoundMax();
+                boundUnits = c.getBoundUnits();
+            }
             peakResponse             = object.getPeakResponse();
             toneGradation            = object.getToneGradation();
             bandBoundaryDefinition   = object.getBandBoundaryDefinition();
@@ -182,9 +190,9 @@
      *
      * @since 0.5
      */
-    @Override
     @ValueRange(minimum = 0)
 /// @XmlElement(name = "boundMin")
+    @UML(identifier="boundMin", obligation=OPTIONAL, specification=ISO_19115)
     public Double getBoundMin() {
         return boundMin;
     }
@@ -213,9 +221,9 @@
      *
      * @since 0.5
      */
-    @Override
     @ValueRange(minimum = 0)
 /// @XmlElement(name = "boundMax")
+    @UML(identifier="boundMax", obligation=OPTIONAL, specification=ISO_19115)
     public Double getBoundMax() {
         return boundMax;
     }
@@ -242,8 +250,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "boundUnits")
+    @UML(identifier="boundUnits", obligation=OPTIONAL, specification=ISO_19115)
     public Unit<Length> getBoundUnits() {
         return boundUnits;
     }
@@ -282,6 +290,39 @@
     }
 
     /**
+     * Returns the units of data as a unit of length.
+     *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * As of ISO 19115:2014, the units of wavelength is rather {@code boundUnits}.
+     * The restriction for units of length in this {@code units} property may be relaxed in GeoAPI 4.0.
+     * </div>
+     *
+     * @return The units of data.
+     */
+    @Override
+    public Unit<Length> getUnits() {
+        final Unit<?> units = super.getUnits();
+        return (units != null) ? units.asType(Length.class) : null;
+    }
+
+    /**
+     * Sets the units of data as a unit of length.
+     *
+     * <div class="warning"><b>Upcoming precondition change — relaxation</b><br>
+     * The current implementation requires the unit to be an instance of {@code Unit<Length>},
+     * otherwise a {@link ClassCastException} is thrown. This is because the value returned by
+     * {@link #getUnits()} was restricted by ISO 19115:2003 to units of length.
+     * However this restriction may be relaxed in GeoAPI 4.0.
+     * </div>
+     *
+     * @param newValue The new units of data as an instance of {@code Unit<Length>}.
+     */
+    @Override
+    public void setUnits(final Unit<?> newValue) {
+        super.setUnits(newValue.asType(Length.class));
+    }
+
+    /**
      * Returns the wavelength at which the response is the highest.
      * The units of measurement is given by {@link #getBoundUnits()}.
      *
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
index 6486b78..22e0e8b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
@@ -22,8 +22,8 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.Identifier;
-import org.opengis.metadata.content.AttributeGroup;
 import org.opengis.metadata.content.CoverageContentType;
 import org.opengis.metadata.content.CoverageDescription;
 import org.opengis.metadata.content.ImageDescription;
@@ -32,6 +32,8 @@
 import org.opengis.util.RecordType;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 
 
 /**
@@ -83,7 +85,7 @@
     /**
      * Information on attribute groups of the resource.
      */
-    private Collection<AttributeGroup> attributeGroups;
+    private Collection<DefaultAttributeGroup> attributeGroups;
 
     /**
      * Provides the description of the specific range elements of a coverage.
@@ -109,9 +111,11 @@
         super(object);
         if (object != null) {
             attributeDescription     = object.getAttributeDescription();
-            processingLevelCode      = object.getProcessingLevelCode();
-            attributeGroups          = copyCollection(object.getAttributeGroups(), AttributeGroup.class);
             rangeElementDescriptions = copyCollection(object.getRangeElementDescriptions(), RangeElementDescription.class);
+            if (object instanceof DefaultCoverageDescription) {
+                processingLevelCode  = ((DefaultCoverageDescription) object).getProcessingLevelCode();
+                attributeGroups      = copyCollection(((DefaultCoverageDescription) object).getAttributeGroups(), DefaultAttributeGroup.class);
+            }
         }
     }
 
@@ -174,8 +178,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "processingLevelCode")
+    @UML(identifier="processingLevelCode", obligation=OPTIONAL, specification=ISO_19115)
     public Identifier getProcessingLevelCode() {
         return processingLevelCode;
     }
@@ -195,25 +199,35 @@
     /**
      * Returns information on attribute groups of the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code AttributeGroup} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information on attribute groups of the resource.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "attributeGroup")
-    public Collection<AttributeGroup> getAttributeGroups() {
-        return attributeGroups = nonNullCollection(attributeGroups, AttributeGroup.class);
+    @UML(identifier="attributeGroup", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultAttributeGroup> getAttributeGroups() {
+        return attributeGroups = nonNullCollection(attributeGroups, DefaultAttributeGroup.class);
     }
 
     /**
      * Sets information on attribute groups of the resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code AttributeGroup} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new information on attribute groups of the resource.
      *
      * @since 0.5
      */
-    public void setAttributeGroups(final Collection<? extends AttributeGroup> newValues) {
-        attributeGroups = writeCollection(newValues, attributeGroups, AttributeGroup.class);
+    public void setAttributeGroups(final Collection<? extends DefaultAttributeGroup> newValues) {
+        attributeGroups = writeCollection(newValues, attributeGroups, DefaultAttributeGroup.class);
     }
 
     /**
@@ -229,9 +243,9 @@
     @XmlElement(name = "contentType", required = true)
     public CoverageContentType getContentType() {
         CoverageContentType type = null;
-        final Collection<AttributeGroup> groups = getAttributeGroups();
+        final Collection<DefaultAttributeGroup> groups = getAttributeGroups();
         if (groups != null) { // May be null on marshalling.
-            for (final AttributeGroup g : groups) {
+            for (final DefaultAttributeGroup g : groups) {
                 final Collection<? extends CoverageContentType> contentTypes = g.getContentTypes();
                 if (contentTypes != null) { // May be null on marshalling.
                     for (final CoverageContentType t : contentTypes) {
@@ -261,13 +275,11 @@
     public void setContentType(final CoverageContentType newValue) {
         checkWritePermission();
         final Collection<CoverageContentType> newValues = LegacyPropertyAdapter.asCollection(newValue);
-        Collection<AttributeGroup> groups = attributeGroups;
+        Collection<DefaultAttributeGroup> groups = attributeGroups;
         if (groups != null) {
-            for (final AttributeGroup group : groups) {
-                if (group instanceof DefaultAttributeGroup) {
-                    ((DefaultAttributeGroup) group).setContentTypes(newValues);
-                    return;
-                }
+            for (final DefaultAttributeGroup group : groups) {
+                group.setContentTypes(newValues);
+                return; // Actually stop at the first instance.
             }
         }
         final DefaultAttributeGroup group = new DefaultAttributeGroup();
@@ -275,7 +287,7 @@
         if (groups != null) {
             groups.add(group);
         } else {
-            groups = Collections.<AttributeGroup>singleton(group);
+            groups = Collections.<DefaultAttributeGroup>singleton(group);
         }
         setAttributeGroups(groups);
     }
@@ -292,24 +304,24 @@
     @Deprecated
     @XmlElement(name = "dimension")
     public final Collection<RangeDimension> getDimensions() {
-        return new LegacyPropertyAdapter<RangeDimension,AttributeGroup>(getAttributeGroups()) {
+        return new LegacyPropertyAdapter<RangeDimension,DefaultAttributeGroup>(getAttributeGroups()) {
             /** Stores a legacy value into the new kind of value. */
-            @Override protected AttributeGroup wrap(final RangeDimension value) {
+            @Override protected DefaultAttributeGroup wrap(final RangeDimension value) {
                 final DefaultAttributeGroup container = new DefaultAttributeGroup();
                 container.setAttributes(asCollection(value));
                 return container;
             }
 
             /** Extracts the legacy value from the new kind of value. */
-            @Override protected RangeDimension unwrap(final AttributeGroup container) {
+            @Override protected RangeDimension unwrap(final DefaultAttributeGroup container) {
                 return getSingleton(container.getAttributes(), RangeDimension.class,
                         this, DefaultCoverageDescription.class, "getDimensions");
             }
 
             /** Updates the legacy value in an existing instance of the new kind of value. */
-            @Override protected boolean update(final AttributeGroup container, final RangeDimension value) {
+            @Override protected boolean update(final DefaultAttributeGroup container, final RangeDimension value) {
                 if (container instanceof DefaultAttributeGroup) {
-                    ((DefaultAttributeGroup) container).setAttributes(asCollection(value));
+                    container.setAttributes(asCollection(value));
                     return true;
                 }
                 return false;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
index 2c085f2..d224463 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
@@ -21,12 +21,15 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.content.FeatureCatalogueDescription;
-import org.opengis.metadata.content.FeatureTypeInfo;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information identifying the feature catalogue or the conceptual schema.
@@ -85,7 +88,7 @@
     /**
      * Subset of feature types from cited feature catalogue occurring in resource.
      */
-    private Collection<FeatureTypeInfo> featureTypes;
+    private Collection<DefaultFeatureTypeInfo> featureTypes;
 
     /**
      * Complete bibliographic reference to one or more external feature catalogues.
@@ -113,8 +116,12 @@
             compliant                 = object.isCompliant();
             includedWithDataset       = object.isIncludedWithDataset();
             languages                 = copyCollection(object.getLanguages(), Locale.class);
-            featureTypes              = copyCollection(object.getFeatureTypeInfo(), FeatureTypeInfo.class);
             featureCatalogueCitations = copyCollection(object.getFeatureCatalogueCitations(), Citation.class);
+            if (object instanceof DefaultFeatureCatalogueDescription) {
+                featureTypes = copyCollection(((DefaultFeatureCatalogueDescription) object).getFeatureTypeInfo(), DefaultFeatureTypeInfo.class);
+            } else {
+                setFeatureTypes(object.getFeatureTypes());
+            }
         }
     }
 
@@ -208,24 +215,34 @@
     /**
      * Returns the subset of feature types from cited feature catalogue occurring in resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code FeatureTypeInfo} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Subset of feature types occurring in resource.
      *
      * @since 0.5
      */
-    @Override
-    public Collection<FeatureTypeInfo> getFeatureTypeInfo() {
-        return featureTypes = nonNullCollection(featureTypes, FeatureTypeInfo.class);
+    @UML(identifier="featureTypes", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultFeatureTypeInfo> getFeatureTypeInfo() {
+        return featureTypes = nonNullCollection(featureTypes, DefaultFeatureTypeInfo.class);
     }
 
     /**
      * Sets the subset of feature types from cited feature catalogue occurring in resource.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code FeatureTypeInfo} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new feature types.
      *
      * @since 0.5
      */
-    public void setFeatureTypeInfo(final Collection<? extends FeatureTypeInfo> newValues) {
-        featureTypes = writeCollection(newValues, featureTypes, FeatureTypeInfo.class);
+    public void setFeatureTypeInfo(final Collection<? extends DefaultFeatureTypeInfo> newValues) {
+        featureTypes = writeCollection(newValues, featureTypes, DefaultFeatureTypeInfo.class);
     }
 
     /**
@@ -239,21 +256,21 @@
     @Deprecated
     @XmlElement(name = "featureTypes")
     public final Collection<GenericName> getFeatureTypes() {
-        return new LegacyPropertyAdapter<GenericName,FeatureTypeInfo>(getFeatureTypeInfo()) {
+        return new LegacyPropertyAdapter<GenericName,DefaultFeatureTypeInfo>(getFeatureTypeInfo()) {
             /** Stores a legacy value into the new kind of value. */
-            @Override protected FeatureTypeInfo wrap(final GenericName value) {
+            @Override protected DefaultFeatureTypeInfo wrap(final GenericName value) {
                 return new DefaultFeatureTypeInfo(value);
             }
 
             /** Extracts the legacy value from the new kind of value. */
-            @Override protected GenericName unwrap(final FeatureTypeInfo container) {
+            @Override protected GenericName unwrap(final DefaultFeatureTypeInfo container) {
                 return container.getFeatureTypeName();
             }
 
             /** Updates the legacy value in an existing instance of the new kind of value. */
-            @Override protected boolean update(final FeatureTypeInfo container, final GenericName value) {
+            @Override protected boolean update(final DefaultFeatureTypeInfo container, final GenericName value) {
                 if (container instanceof DefaultFeatureTypeInfo) {
-                    ((DefaultFeatureTypeInfo) container).setFeatureTypeName(value);
+                    container.setFeatureTypeName(value);
                     return true;
                 }
                 return false;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
index be5b314..8c6c742 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
@@ -20,16 +20,29 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.content.FeatureTypeInfo;
 import org.apache.sis.measure.ValueRange;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the occurring feature type.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code FeatureTypeInfo} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -50,7 +63,8 @@
     "featureInstanceCount"
 })
 @XmlRootElement(name = "MD_FeatureTypeInfo")
-public class DefaultFeatureTypeInfo extends ISOMetadata implements FeatureTypeInfo {
+@UML(identifier="MD_FeatureTypeInfo", specification=ISO_19115)
+public class DefaultFeatureTypeInfo extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -94,10 +108,8 @@
      * </div>
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(FeatureTypeInfo)
      */
-    public DefaultFeatureTypeInfo(final FeatureTypeInfo object) {
+    public DefaultFeatureTypeInfo(final DefaultFeatureTypeInfo object) {
         super(object);
         if (object != null) {
             featureTypeName      = object.getFeatureTypeName();
@@ -106,39 +118,14 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultFeatureTypeInfo}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultFeatureTypeInfo} instance is created using the
-     *       {@linkplain #DefaultFeatureTypeInfo(FeatureTypeInfo) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultFeatureTypeInfo castOrCopy(final FeatureTypeInfo object) {
-        if (object == null || object instanceof DefaultFeatureTypeInfo) {
-            return (DefaultFeatureTypeInfo) object;
-        }
-        return new DefaultFeatureTypeInfo(object);
-    }
-
-    /**
      * Returns the name of the feature type.
      *
      * @return Name of the feature type.
      *
      * @see org.apache.sis.feature.DefaultFeatureType#getName()
      */
-    @Override
     @XmlElement(name = "featureTypeName", required = true)
+    @UML(identifier="featureTypeName", obligation=MANDATORY, specification=ISO_19115)
     public GenericName getFeatureTypeName() {
         return featureTypeName;
     }
@@ -158,9 +145,9 @@
      *
      * @return The number of occurrence of feature instances for this feature types, or {@code null} if none.
      */
-    @Override
     @ValueRange(minimum = 1)
     @XmlElement(name = "featureInstanceCount")
+    @UML(identifier="featureInstanceCount", obligation=OPTIONAL, specification=ISO_19115)
     public Integer getFeatureInstanceCount() {
         return featureInstanceCount;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
index 910bcd0..ca9c37c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
@@ -21,13 +21,17 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.MemberName;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.content.RangeDimension;
-import org.opengis.metadata.content.SampleDimension;
+import org.opengis.metadata.content.Band;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information on the range of each dimension of a cell measurement value.
@@ -97,8 +101,10 @@
         super(object);
         if (object != null) {
             sequenceIdentifier = object.getSequenceIdentifier();
-            description        = object.getDescription();
-            names              = copyCollection(object.getNames(), Identifier.class);
+            description        = object.getDescriptor();
+            if (object instanceof DefaultRangeDimension) {
+                names = copyCollection(((DefaultRangeDimension) object).getNames(), Identifier.class);
+            }
         }
     }
 
@@ -123,8 +129,8 @@
      *         given object itself), or {@code null} if the argument was null.
      */
     public static DefaultRangeDimension castOrCopy(final RangeDimension object) {
-        if (object instanceof SampleDimension) {
-            return DefaultSampleDimension.castOrCopy((SampleDimension) object);
+        if (object instanceof Band) {
+            return DefaultBand.castOrCopy((Band) object);
         }
         // Intentionally tested after the sub-interfaces.
         if (object == null || object instanceof DefaultRangeDimension) {
@@ -161,8 +167,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "description")
+    @UML(identifier="description", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDescription() {
         return description;
     }
@@ -215,8 +221,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "name")
+    @UML(identifier="name", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Identifier> getNames() {
         return names = nonNullCollection(names, Identifier.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
index dd1323b..1433c38 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
@@ -21,20 +21,33 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
-import org.opengis.metadata.content.Band;
-import org.opengis.metadata.content.SampleDimension;
 import org.opengis.metadata.content.CoverageContentType;
 import org.opengis.metadata.content.TransferFunctionType;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
+import org.opengis.metadata.content.Band;
 import org.apache.sis.measure.ValueRange;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * The characteristic of each dimension (layer) included in the resource.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code SampleDimension} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -65,7 +78,8 @@
 })
 @XmlRootElement(name = "MD_SampleDimension")
 @XmlSeeAlso({DefaultBand.class, DefaultRangeDimension.class})
-public class DefaultSampleDimension extends DefaultRangeDimension implements SampleDimension {
+@UML(identifier="MD_SampleDimension", specification=ISO_19115)
+public class DefaultSampleDimension extends DefaultRangeDimension {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -161,54 +175,49 @@
      *
      * @see #castOrCopy(SampleDimension)
      */
-    public DefaultSampleDimension(final SampleDimension object) {
+    public DefaultSampleDimension(final DefaultSampleDimension object) {
         super(object);
         if (object != null) {
-            minValue                 = object.getMinValue();
-            maxValue                 = object.getMaxValue();
-            meanValue                = object.getMeanValue();
-            numberOfValues           = object.getNumberOfValues();
-            standardDeviation        = object.getStandardDeviation();
-            units                    = object.getUnits();
-            scaleFactor              = object.getScaleFactor();
-            offset                   = object.getOffset();
-            transferFunctionType     = object.getTransferFunctionType();
-            bitsPerValue             = object.getBitsPerValue();
-            nominalSpatialResolution = object.getNominalSpatialResolution();
-            otherPropertyType        = object.getOtherPropertyType();
-            otherProperty            = object.getOtherProperty();
+            init(object);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is is an instance of {@link Band}, then this
-     *       method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultSampleDimension}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultSampleDimension} instance is created using the
-     *       {@linkplain #DefaultSampleDimension(SampleDimension) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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.
+     * Initializes this sample dimension to the values of the given object.
      */
-    public static DefaultSampleDimension castOrCopy(final SampleDimension object) {
-        if (object instanceof Band) {
-            return DefaultBand.castOrCopy((Band) object);
+    private void init(final DefaultSampleDimension object) {
+        minValue                 = object.getMinValue();
+        maxValue                 = object.getMaxValue();
+        meanValue                = object.getMeanValue();
+        numberOfValues           = object.getNumberOfValues();
+        standardDeviation        = object.getStandardDeviation();
+        units                    = object.getUnits();
+        scaleFactor              = object.getScaleFactor();
+        offset                   = object.getOffset();
+        transferFunctionType     = object.getTransferFunctionType();
+        bitsPerValue             = object.getBitsPerValue();
+        nominalSpatialResolution = object.getNominalSpatialResolution();
+        otherPropertyType        = object.getOtherPropertyType();
+        otherProperty            = object.getOtherProperty();
+    }
+
+    /**
+     * Bridge constructor for {@link DefaultBand#DefaultBand(Band)}.
+     */
+    DefaultSampleDimension(final Band object) {
+        super(object);
+        if (object != null) {
+            if (object instanceof DefaultSampleDimension) {
+                init((DefaultSampleDimension) object);
+            } else {
+                maxValue     = object.getMaxValue();
+                minValue     = object.getMinValue();
+                units        = object.getUnits();
+                scaleFactor  = object.getScaleFactor();
+                offset       = object.getOffset();
+                bitsPerValue = object.getBitsPerValue();
+            }
         }
-        //-- Intentionally tested after the sub-interfaces.
-        if (object == null || object instanceof DefaultSampleDimension) {
-            return (DefaultSampleDimension) object;
-        }
-        return new DefaultSampleDimension(object);
     }
 
     /**
@@ -216,8 +225,8 @@
      *
      * @return Minimum value of data values in each dimension included in the resource, or {@code null} if unspecified.
      */
-    @Override
     @XmlElement(name = "minValue")
+    @UML(identifier="minValue", obligation=OPTIONAL, specification=ISO_19115)
     public Double getMinValue() {
         return minValue;
     }
@@ -237,8 +246,8 @@
      *
      * @return Maximum value of data values in each dimension included in the resource, or {@code null} if unspecified.
      */
-    @Override
     @XmlElement(name = "maxValue")
+    @UML(identifier="maxValue", obligation=OPTIONAL, specification=ISO_19115)
     public Double getMaxValue() {
         return maxValue;
     }
@@ -258,8 +267,8 @@
      *
      * @return The mean value of data values in each dimension included in the resource, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "meanValue")
+    @UML(identifier="meanValue", obligation=OPTIONAL, specification=ISO_19115)
     public Double getMeanValue() {
         return meanValue;
     }
@@ -279,9 +288,9 @@
      *
      * @return The number of values used in a thematic classification resource, or {@code null} if none.
      */
-    @Override
     @ValueRange(minimum = 0)
 /// @XmlElement(name = "numberOfValues")
+    @UML(identifier="numberOfValues", obligation=OPTIONAL, specification=ISO_19115)
     public Integer getNumberOfValues() {
         return numberOfValues;
     }
@@ -304,8 +313,8 @@
      *
      * @return Standard deviation of data values in each dimension included in the resource, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "standardDeviation")
+    @UML(identifier="standardDeviation", obligation=OPTIONAL, specification=ISO_19115)
     public Double getStandardDeviation() {
         return standardDeviation;
     }
@@ -325,8 +334,8 @@
      *
      * @return The units of data in the dimension, or {@code null} if unspecified.
      */
-    @Override
     @XmlElement(name = "units")
+    @UML(identifier="units", obligation=CONDITIONAL, specification=ISO_19115)
     public Unit<?> getUnits() {
         return units;
     }
@@ -346,8 +355,8 @@
      *
      * @return Scale factor which has been applied to the cell value, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "scaleFactor")
+    @UML(identifier="scaleFactor", obligation=OPTIONAL, specification=ISO_19115)
     public Double getScaleFactor() {
         return scaleFactor;
     }
@@ -367,8 +376,8 @@
      *
      * @return The physical value corresponding to a cell value of zero, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "offset")
+    @UML(identifier="offset", obligation=OPTIONAL, specification=ISO_19115)
     public Double getOffset() {
         return offset;
     }
@@ -388,7 +397,6 @@
      *
      * @return Type of transfer function, or {@code null}.
      */
-    @Override
     public TransferFunctionType getTransferFunctionType() {
         return transferFunctionType;
     }
@@ -410,9 +418,9 @@
      * @return Maximum number of significant bits in the uncompressed representation
      *         for the value in each band of each pixel, or {@code null} if none.
      */
-    @Override
     @ValueRange(minimum = 1)
 /// @XmlElement(name = "bitsPerValues")
+    @UML(identifier="bitsPerValue", obligation=OPTIONAL, specification=ISO_19115)
     public Integer getBitsPerValue() {
         return bitsPerValue;
     }
@@ -437,7 +445,6 @@
      *
      * @return Smallest distance between which separate points can be distinguished, or {@code null}.
      */
-    @Override
     @ValueRange(minimum = 0, isMinIncluded = false)
     public Double getNominalSpatialResolution() {
         return nominalSpatialResolution;
@@ -462,8 +469,8 @@
      *
      * @return Type of other attribute description, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "otherPropertyType")
+    @UML(identifier="otherPropertyType", obligation=OPTIONAL, specification=ISO_19115)
     public RecordType getOtherPropertyType() {
         return otherPropertyType;
     }
@@ -484,8 +491,8 @@
      *
      * @return instance of other/attributeType that defines attributes, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "otherProperty")
+    @UML(identifier="otherProperty", obligation=OPTIONAL, specification=ISO_19115)
     public Record getOtherProperty() {
         return otherProperty;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
index a34cde7..8435b73 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
@@ -20,6 +20,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.temporal.PeriodDuration;
 import org.opengis.metadata.citation.OnlineResource;
@@ -32,6 +33,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Technical means and media by which a resource is obtained from the distributor.
@@ -124,9 +129,14 @@
             unitsOfDistribution = object.getUnitsOfDistribution();
             transferSize        = object.getTransferSize();
             onLines             = copyCollection(object.getOnLines(), OnlineResource.class);
-            offLines            = copyCollection(object.getOffLines(), Medium.class);
-            transferFrequency   = object.getTransferFrequency();
-            distributionFormats = copyCollection(object.getDistributionFormats(), Format.class);
+            if (object instanceof DefaultDigitalTransferOptions) {
+                final DefaultDigitalTransferOptions c = (DefaultDigitalTransferOptions) object;
+                offLines            = copyCollection(c.getOffLines(), Medium.class);
+                transferFrequency   = c.getTransferFrequency();
+                distributionFormats = copyCollection(c.getDistributionFormats(), Format.class);
+            } else {
+                offLines = singleton(object.getOffLine(), Medium.class);
+            }
         }
     }
 
@@ -230,7 +240,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="offLine", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Medium> getOffLines() {
         return offLines = nonNullCollection(offLines, Medium.class);
     }
@@ -279,7 +289,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="transferFrequency", obligation=OPTIONAL, specification=ISO_19115)
     public PeriodDuration getTransferFrequency() {
         return transferFrequency;
     }
@@ -303,7 +313,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="distributionFormat", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Format> getDistributionFormats() {
         return distributionFormats = nonNullCollection(distributionFormats, Format.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
index 6f00d8d..1f36ec1 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
@@ -20,6 +20,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.distribution.DigitalTransferOptions;
 import org.opengis.metadata.distribution.Distribution;
@@ -27,6 +28,9 @@
 import org.opengis.metadata.distribution.Format;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the distributor of and options for obtaining the resource.
@@ -98,10 +102,12 @@
     public DefaultDistribution(final Distribution object) {
         super(object);
         if (object != null) {
-            description         = object.getDescription();
             distributionFormats = copyCollection(object.getDistributionFormats(), Format.class);
             distributors        = copyCollection(object.getDistributors(), Distributor.class);
             transferOptions     = copyCollection(object.getTransferOptions(), DigitalTransferOptions.class);
+            if (object instanceof DefaultDistribution) {
+                description = ((DefaultDistribution) object).getDescription();
+            }
         }
     }
 
@@ -137,7 +143,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="description", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDescription() {
         return description;
     }
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 4ec7720..9e90ac8 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;
@@ -58,12 +58,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
@@ -92,7 +92,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;
     }
 
@@ -143,20 +143,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 {@link 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 {@link 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 = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
index 07dec8c..d2816db 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
@@ -21,6 +21,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.distribution.Format;
@@ -33,6 +34,9 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.BiConsumer;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
 
 
 /**
@@ -129,11 +133,17 @@
     public DefaultFormat(final Format object) {
         super(object);
         if (object != null) {
-            formatSpecificationCitation = object.getFormatSpecificationCitation();
             amendmentNumber             = object.getAmendmentNumber();
             fileDecompressionTechnique  = object.getFileDecompressionTechnique();
-            media                       = copyCollection(object.getMedia(), Medium.class);
             formatDistributors          = copyCollection(object.getFormatDistributors(), Distributor.class);
+            if (object instanceof DefaultFormat) {
+                formatSpecificationCitation = ((DefaultFormat) object).getFormatSpecificationCitation();
+                media = copyCollection(((DefaultFormat) object).getMedia(), Medium.class);
+            } else {
+                setSpecification(object.getSpecification());
+                setVersion(object.getVersion());
+                setName(object.getName());
+            }
         }
     }
 
@@ -169,8 +179,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "formatSpecificationCitation", required = true)
+    @UML(identifier="formatSpecificationCitation", obligation=MANDATORY, specification=ISO_19115)
     public Citation getFormatSpecificationCitation() {
         return formatSpecificationCitation;
     }
@@ -371,8 +381,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "medium")
+    @UML(identifier="medium", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Medium> getMedia() {
         return media = nonNullCollection(media, Medium.class);
     }
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 cd802ad..151b0c9 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
@@ -16,13 +16,12 @@
  */
 package org.apache.sis.metadata.iso.distribution;
 
-import java.util.AbstractSet;
 import java.util.Collection;
-import java.util.Iterator;
 import javax.measure.unit.Unit;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.distribution.Medium;
@@ -35,6 +34,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the media on which the resource can be distributed.
@@ -68,7 +71,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 2657393801067168091L;
+    private static final long serialVersionUID = 7751002701087451894L;
 
     /**
      * Name of the medium on which the resource can be received.
@@ -79,7 +82,7 @@
      * Density at which the data is recorded.
      * If non-null, then the number shall be greater than zero.
      */
-    private Double density;
+    private Collection<Double> densities;
 
     /**
      * Units of measure for the recording density.
@@ -127,12 +130,14 @@
         super(object);
         if (object != null) {
             name          = object.getName();
-            density       = object.getDensity();
+            densities     = copyCollection(object.getDensities(), Double.class);
             densityUnits  = object.getDensityUnits();
             volumes       = object.getVolumes();
             mediumFormats = copyCollection(object.getMediumFormats(), MediumFormat.class);
             mediumNote    = object.getMediumNote();
-            identifiers   = singleton(object.getIdentifier(), Identifier.class);
+            if (object instanceof DefaultMedium) {
+                identifiers = singleton(((DefaultMedium) object).getIdentifier(), Identifier.class);
+            }
         }
     }
 
@@ -190,10 +195,10 @@
      *
      * @since 0.5
      */
-    @Override
     @ValueRange(minimum = 0, isMinIncluded = false)
+    @UML(identifier="density", obligation=OPTIONAL, specification=ISO_19115)
     public Double getDensity() {
-        return density;
+        return LegacyPropertyAdapter.getSingleton(densities, Double.class, null, DefaultMedium.class, "getDensity");
     }
 
     /**
@@ -208,7 +213,7 @@
     public void setDensity(final Double newValue) {
         checkWritePermission();
         if (ensurePositive(DefaultMedium.class, "density", true, newValue)) {
-            density = newValue;
+            densities = writeCollection(LegacyPropertyAdapter.asCollection(newValue), densities, Double.class);
         }
     }
 
@@ -221,28 +226,7 @@
     @Deprecated
     @XmlElement(name = "density")
     public Collection<Double> getDensities() {
-        return new AbstractSet<Double>() {
-            /** Returns 0 if empty, or 1 if a density has been specified. */
-            @Override public int size() {
-                return getDensity() != null ? 1 : 0;
-            }
-
-            /** Returns an iterator over 0 or 1 element. Current iterator implementation is unmodifiable. */
-            @Override public Iterator<Double> iterator() {
-                return LegacyPropertyAdapter.asCollection(getDensity()).iterator();
-            }
-
-            /** Adds an element only if the set is empty. This method is invoked by JAXB at unmarshalling time. */
-            @Override public boolean add(final Double newValue) {
-                if (isEmpty()) {
-                    setDensity(newValue);
-                    return true;
-                } else {
-                    LegacyPropertyAdapter.warnIgnoredExtraneous(Double.class, DefaultMedium.class, "setDensities");
-                    return false;
-                }
-            }
-        };
+        return densities = nonNullCollection(densities, Double.class);
     }
 
     /**
@@ -252,7 +236,7 @@
      */
     @Deprecated
     public void setDensities(final Collection<? extends Double> newValues) {
-        setDensity(LegacyPropertyAdapter.getSingleton(newValues, Double.class, null, DefaultMedium.class, "setDensities"));
+        densities = writeCollection(newValues, densities, Double.class);
     }
 
     /**
@@ -349,8 +333,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "identifier")
+    @UML(identifier="identifier", obligation=OPTIONAL, specification=ISO_19115)
     public Identifier getIdentifier() {
         return NonMarshalledAuthority.getMarshallable(identifiers);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
index 1cf30a5..be1bd06 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
@@ -21,12 +21,15 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.opengis.annotation.UML;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.distribution.StandardOrderProcess;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
 
@@ -123,8 +126,10 @@
             plannedAvailableDateTime = toMilliseconds(object.getPlannedAvailableDateTime());
             orderingInstructions     = object.getOrderingInstructions();
             turnaround               = object.getTurnaround();
-            orderOptionType          = object.getOrderOptionType();
-            orderOptions             = object.getOrderOptions();
+            if (object instanceof DefaultStandardOrderProcess) {
+                orderOptionType = ((DefaultStandardOrderProcess) object).getOrderOptionType();
+                orderOptions    = ((DefaultStandardOrderProcess) object).getOrderOptions();
+            }
         }
     }
 
@@ -196,7 +201,6 @@
      *
      * @see #getFees()
      */
-    @Override
     public Currency getCurrency() {
         return currency;
     }
@@ -289,8 +293,8 @@
      *
      * @see org.apache.sis.util.iso.DefaultRecord#getRecordType()
      */
-    @Override
 /// @XmlElement(name = "orderOptionType")
+    @UML(identifier="orderOptionType", obligation=OPTIONAL, specification=ISO_19115)
     public RecordType getOrderOptionType() {
         return orderOptionType;
     }
@@ -318,8 +322,8 @@
      *       when he ordered the resource. We presume that this is not a record to be filled by the user for new
      *       orders, otherwise this method would need to be a factory rather than a getter.
      */
-    @Override
 /// @XmlElement(name = "orderOptions")
+    @UML(identifier="orderOptions", obligation=OPTIONAL, specification=ISO_19115)
     public Record getOrderOptions() {
         return orderOptions;
     }
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 6f6eb06..ad4b41b 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
@@ -88,7 +88,7 @@
     @XmlJavaTypeAdapter(MD_MediumFormatCode.class),
     @XmlJavaTypeAdapter(MD_MediumNameCode.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.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/extent/DefaultSpatialTemporalExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
index 049601c..3bdd0d4 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
@@ -20,6 +20,7 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.geometry.Envelope;
 import org.opengis.metadata.extent.TemporalExtent;
 import org.opengis.metadata.extent.VerticalExtent;
@@ -29,6 +30,9 @@
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.internal.metadata.ReferencingServices;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Extent with respect to date/time and spatial boundaries.
@@ -106,7 +110,9 @@
         super(object);
         if (object != null) {
             spatialExtent  = copyCollection(object.getSpatialExtent(), GeographicExtent.class);
-            verticalExtent = object.getVerticalExtent();
+            if (object instanceof DefaultSpatialTemporalExtent) {
+                verticalExtent = ((DefaultSpatialTemporalExtent) object).getVerticalExtent();
+            }
         }
     }
 
@@ -162,8 +168,8 @@
      *
      * @since 0.5
      */
-    @Override
     @XmlElement(name = "verticalExtent")
+    @UML(identifier="verticalExtent", obligation=OPTIONAL, specification=ISO_19115)
     public VerticalExtent getVerticalExtent() {
         return verticalExtent;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
index 9701543..f078958 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
@@ -22,8 +22,8 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.geometry.Envelope;
-import org.opengis.temporal.Period;
-import org.opengis.temporal.Instant;
+import org.apache.sis.internal.geoapi.temporal.Period;
+import org.apache.sis.internal.geoapi.temporal.Instant;
 import org.opengis.temporal.TemporalPrimitive;
 import org.opengis.metadata.extent.TemporalExtent;
 import org.opengis.metadata.extent.SpatialTemporalExtent;
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 c173691..37a238c 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
@@ -16,19 +16,21 @@
  */
 package org.apache.sis.metadata.iso.identification;
 
+import java.util.List;
+import java.util.ArrayList;
 import java.util.Collection;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 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;
 import org.opengis.metadata.identification.AggregateInformation;
-import org.opengis.metadata.identification.AssociatedResource;
 import org.opengis.metadata.identification.Identification;
 import org.opengis.metadata.identification.DataIdentification;
 import org.opengis.metadata.identification.BrowseGraphic;
@@ -40,12 +42,15 @@
 import org.opengis.metadata.identification.ServiceIdentification;
 import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
-import org.opengis.temporal.Duration;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Basic information required to uniquely identify a resource or resources.
@@ -112,7 +117,7 @@
     /**
      * Recognition of those who contributed to the resource(s).
      */
-    private Collection<InternationalString> credits;
+    private Collection<String> credits;
 
     /**
      * Status of the resource(s).
@@ -123,7 +128,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.
@@ -136,11 +141,6 @@
     private Collection<Resolution> spatialResolutions;
 
     /**
-     * Smallest resolvable temporal period in a resource.
-     */
-    private Collection<Duration> temporalResolutions;
-
-    /**
      * Main theme(s) of the resource.
      */
     private Collection<TopicCategory> topicCategories;
@@ -194,7 +194,7 @@
     /**
      * Provides aggregate dataset information.
      */
-    private Collection<AssociatedResource> associatedResources;
+    private Collection<DefaultAssociatedResource> associatedResources;
 
     /**
      * Constructs an initially empty identification.
@@ -228,23 +228,27 @@
             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);
-            spatialRepresentationTypes = copyCollection(object.getSpatialRepresentationTypes(), SpatialRepresentationType.class);
-            spatialResolutions         = copyCollection(object.getSpatialResolutions(), Resolution.class);
-            temporalResolutions        = copyCollection(object.getTemporalResolutions(), Duration.class);
-            topicCategories            = copyCollection(object.getTopicCategories(), TopicCategory.class);
-            extents                    = copyCollection(object.getExtents(), Extent.class);
-            additionalDocumentations   = copyCollection(object.getAdditionalDocumentations(), Citation.class);
-            processingLevel            = object.getProcessingLevel();
+            pointOfContacts            = copyCollection(object.getPointOfContacts(), ResponsibleParty.class);
             resourceMaintenances       = copyCollection(object.getResourceMaintenances(), MaintenanceInformation.class);
             graphicOverviews           = copyCollection(object.getGraphicOverviews(), BrowseGraphic.class);
             resourceFormats            = copyCollection(object.getResourceFormats(), Format.class);
             descriptiveKeywords        = copyCollection(object.getDescriptiveKeywords(), Keywords.class);
             resourceSpecificUsages     = copyCollection(object.getResourceSpecificUsages(), Usage.class);
             resourceConstraints        = copyCollection(object.getResourceConstraints(), Constraints.class);
-            associatedResources        = copyCollection(object.getAssociatedResources(), AssociatedResource.class);
+            if (object instanceof AbstractIdentification) {
+                final AbstractIdentification c = (AbstractIdentification) object;
+                spatialRepresentationTypes = copyCollection(c.getSpatialRepresentationTypes(), SpatialRepresentationType.class);
+                spatialResolutions         = copyCollection(c.getSpatialResolutions(), Resolution.class);
+                topicCategories            = copyCollection(c.getTopicCategories(), TopicCategory.class);
+                extents                    = copyCollection(c.getExtents(), Extent.class);
+                additionalDocumentations   = copyCollection(c.getAdditionalDocumentations(), Citation.class);
+                processingLevel            = c.getProcessingLevel();
+                associatedResources        = copyCollection(c.getAssociatedResources(), DefaultAssociatedResource.class);
+            } else {
+                setAggregationInfo(object.getAggregationInfo());
+            }
         }
     }
 
@@ -351,21 +355,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);
     }
 
     /**
@@ -392,23 +404,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 {@link 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 {@link 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);
     }
 
     /**
@@ -418,8 +440,8 @@
      *
      * @since 0.5
      */
-    @Override
     @XmlElement(name = "spatialRepresentationType")
+    @UML(identifier="spatialRepresentationType", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<SpatialRepresentationType> getSpatialRepresentationTypes() {
         return spatialRepresentationTypes = nonNullCollection(spatialRepresentationTypes, SpatialRepresentationType.class);
     }
@@ -443,8 +465,8 @@
      *
      * @since 0.5
      */
-    @Override
     @XmlElement(name = "spatialResolution")
+    @UML(identifier="spatialResolution", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Resolution> getSpatialResolutions() {
         return spatialResolutions = nonNullCollection(spatialResolutions, Resolution.class);
     }
@@ -461,38 +483,14 @@
     }
 
     /**
-     * Returns the smallest resolvable temporal period in a resource.
-     *
-     * @return Smallest resolvable temporal period in a resource.
-     *
-     * @since 0.5
-     */
-    @Override
-/// @XmlElement(name = "temporalResolution")
-    public Collection<Duration> getTemporalResolutions() {
-        return temporalResolutions = nonNullCollection(temporalResolutions, Duration.class);
-    }
-
-    /**
-     * Sets the smallest resolvable temporal period in a resource.
-     *
-     * @param newValues The new temporal resolutions.
-     *
-     * @since 0.5
-     */
-    public void setTemporalResolutions(final Collection<? extends Duration> newValues) {
-        temporalResolutions = writeCollection(newValues, temporalResolutions, Duration.class);
-    }
-
-    /**
      * Returns the main theme(s) of the resource.
      *
      * @return Main theme(s).
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "topicCategory")
+    @UML(identifier="topicCategory", obligation=CONDITIONAL, specification=ISO_19115)
     public Collection<TopicCategory> getTopicCategories()  {
         return topicCategories = nonNullCollection(topicCategories, TopicCategory.class);
     }
@@ -515,8 +513,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "extent")
+    @UML(identifier="extent", obligation=CONDITIONAL, specification=ISO_19115)
     public Collection<Extent> getExtents() {
         return extents = nonNullCollection(extents, Extent.class);
     }
@@ -539,8 +537,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "additionalDocumentation")
+    @UML(identifier="additionalDocumentation", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getAdditionalDocumentations() {
         return additionalDocumentations = nonNullCollection(additionalDocumentations, Citation.class);
     }
@@ -563,8 +561,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "processingLevel")
+    @UML(identifier="processingLevel", obligation=OPTIONAL, specification=ISO_19115)
     public Identifier getProcessingLevel() {
         return processingLevel;
     }
@@ -706,25 +704,35 @@
     /**
      * Provides associated resource information.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code AssociatedResource} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Associated resource information.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "associatedResource")
-    public Collection<AssociatedResource> getAssociatedResources() {
-        return associatedResources = nonNullCollection(associatedResources, AssociatedResource.class);
+    @UML(identifier="associatedResource", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultAssociatedResource> getAssociatedResources() {
+        return associatedResources = nonNullCollection(associatedResources, DefaultAssociatedResource.class);
     }
 
     /**
      * Sets associated resource information.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code AssociatedResource} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new associated resources.
      *
      * @since 0.5
      */
-    public void setAssociatedResources(final Collection<? extends AssociatedResource> newValues) {
-        associatedResources = writeCollection(newValues, associatedResources, AssociatedResource.class);
+    public void setAssociatedResources(final Collection<? extends DefaultAssociatedResource> newValues) {
+        associatedResources = writeCollection(newValues, associatedResources, DefaultAssociatedResource.class);
     }
 
     /**
@@ -738,16 +746,20 @@
     @Deprecated
     @XmlElement(name = "aggregationInfo")
     public Collection<AggregateInformation> getAggregationInfo() {
-        return new LegacyPropertyAdapter<AggregateInformation,AssociatedResource>(getAssociatedResources()) {
-            @Override protected AssociatedResource wrap(final AggregateInformation value) {
-                return value;
+        return new LegacyPropertyAdapter<AggregateInformation,DefaultAssociatedResource>(getAssociatedResources()) {
+            @Override protected DefaultAssociatedResource wrap(final AggregateInformation value) {
+                return DefaultAssociatedResource.castOrCopy(value);
             }
 
-            @Override protected AggregateInformation unwrap(final AssociatedResource container) {
-                return DefaultAggregateInformation.castOrCopy(container);
+            @Override protected AggregateInformation unwrap(final DefaultAssociatedResource container) {
+                if (container instanceof AggregateInformation) {
+                    return (AggregateInformation) container;
+                } else {
+                    return new DefaultAggregateInformation(container);
+                }
             }
 
-            @Override protected boolean update(final AssociatedResource container, final AggregateInformation value) {
+            @Override protected boolean update(final DefaultAssociatedResource container, final AggregateInformation value) {
                 return container == value;
             }
         }.validOrNull();
@@ -762,6 +774,19 @@
      */
     @Deprecated
     public void setAggregationInfo(final Collection<? extends AggregateInformation> newValues) {
-        setAssociatedResources(newValues);
+        checkWritePermission();
+        /*
+         * We can not invoke getAggregationInfo().setValues(newValues) because this method
+         * is invoked by the constructor, which is itself invoked at JAXB marshalling time,
+         * in which case getAggregationInfo() may return null.
+         */
+        List<DefaultAssociatedResource> r = null;
+        if (newValues != null) {
+            r = new ArrayList<DefaultAssociatedResource>(newValues.size());
+            for (final AggregateInformation value : newValues) {
+                r.add(DefaultAssociatedResource.castOrCopy(value));
+            }
+        }
+        setAssociatedResources(r);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
index 4bbff1e..eb59b09 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
@@ -25,18 +25,23 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.identification.AggregateInformation;
-import org.opengis.metadata.identification.AssociatedResource;
 import org.opengis.metadata.identification.AssociationType;
 import org.opengis.metadata.identification.InitiativeType;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 
 
 /**
- * Aggregate dataset information.
+ * Associated resource information.
  *
  * <div class="section">Relationship between properties</div>
- * According ISO 19115, at least one of {@linkplain #getAggregateDataSetName() aggregate dataset name}
- * and {@linkplain #getAggregateDataSetIdentifier() aggregate dataset identifier} shall be provided.
+ * According ISO 19115, at least one of {@linkplain #getName() name} and
+ * {@linkplain #getMetadataReference() metadata reference} shall be provided.
+ *
+ * <div class="warning"><b>Upcoming API change — renaming</b><br>
+ * As of ISO 19115:2014, {@code AggregateInformation} has been renamed {@code AssociatedResource}.
+ * This class will be replaced by {@link DefaultAssociatedResource} when GeoAPI will provide the
+ * {@code AssociatedResource} interface (tentatively in GeoAPI 3.1 or 4.0).
+ * </div>
  *
  * <div class="section">Limitations</div>
  * <ul>
@@ -52,10 +57,7 @@
  * @since   0.3
  * @version 0.5
  * @module
- *
- * @deprecated As of ISO 19115:2014, replaced by {@link DefaultAssociatedResource}.
  */
-@Deprecated
 @XmlType(name = "MD_AggregateInformation_Type", propOrder = {
     "aggregateDataSetName",
     "aggregateDataSetIdentifier",
@@ -77,6 +79,15 @@
 
     /**
      * Constructs a new instance initialized with the values from the specified metadata object.
+     *
+     * @param object The metadata to copy values from.
+     */
+    DefaultAggregateInformation(final DefaultAssociatedResource object) {
+        super(object);
+    }
+
+    /**
+     * Constructs a new instance initialized with the values from the specified metadata object.
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
@@ -84,8 +95,12 @@
      *
      * @see #castOrCopy(AssociatedResource)
      */
-    public DefaultAggregateInformation(final AssociatedResource object) {
+    public DefaultAggregateInformation(final AggregateInformation object) {
         super(object);
+        if (object != null && !(object instanceof DefaultAssociatedResource)) {
+            setAggregateDataSetName(object.getAggregateDataSetName());
+            setAggregateDataSetIdentifier(object.getAggregateDataSetIdentifier());
+        }
     }
 
     /**
@@ -106,7 +121,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 DefaultAggregateInformation castOrCopy(final AssociatedResource object) {
+    public static DefaultAggregateInformation castOrCopy(final AggregateInformation object) {
         if (object == null || object instanceof DefaultAggregateInformation) {
             return (DefaultAggregateInformation) object;
         }
@@ -206,9 +221,9 @@
     }
 
     /**
-     * Association type of the aggregate dataset.
+     * Returns the type of relation between the resources.
      *
-     * @return Association type of the aggregate dataset.
+     * @return Type of relation between the resources.
      */
     @Override
     @XmlElement(name = "associationType", required = true)
@@ -217,9 +232,9 @@
     }
 
     /**
-     * Sets the association type of the aggregate dataset.
+     * Sets the type of relation between the resources.
      *
-     * @param newValue The new association type.
+     * @param newValue The new type of relation.
      */
     @Override
     public void setAssociationType(final AssociationType newValue) {
@@ -227,9 +242,9 @@
     }
 
     /**
-     * Type of initiative under which the aggregate dataset was produced.
+     * Returns the type of initiative under which the associated resource was produced, or {@code null} if none.
      *
-     * @return Type of initiative under which the aggregate dataset was produced, or {@code null}.
+     * @return The type of initiative under which the associated resource was produced, or {@code null} if none.
      */
     @Override
     @XmlElement(name = "initiativeType")
@@ -238,9 +253,9 @@
     }
 
     /**
-     * Sets the type of initiative under which the aggregate dataset was produced.
+     * Sets a new type of initiative under which the associated resource was produced.
      *
-     * @param newValue The new initiative.
+     * @param newValue The new type of initiative.
      */
     @Override
     public void setInitiativeType(final InitiativeType newValue) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
index 55d2971..d904732 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
@@ -20,11 +20,18 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.AssociatedResource;
+import org.opengis.metadata.identification.AggregateInformation;
 import org.opengis.metadata.identification.AssociationType;
 import org.opengis.metadata.identification.InitiativeType;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+// Branch-specific imports.
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Associated resource information.
@@ -55,7 +62,8 @@
     "metadataReference"
 }*/)
 @XmlRootElement(name = "MD_AssociatedResource")
-public class DefaultAssociatedResource extends ISOMetadata implements AssociatedResource {
+@UML(identifier="MD_AssociatedResource", specification=ISO_19115)
+public class DefaultAssociatedResource extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -100,41 +108,43 @@
 
     /**
      * Constructs a new instance initialized with the values from the specified metadata object.
+     * This is a constructor for {@link DefaultAggregateInformation} constructor only.
+     *
+     * @param object The metadata to copy values from.
+     */
+    DefaultAssociatedResource(final DefaultAssociatedResource object) {
+        this.associationType   = object.associationType;
+        this.initiativeType    = object.initiativeType;
+        this.name              = object.name;
+        this.metadataReference = object.metadataReference;
+    }
+
+    /**
+     * Constructs a new instance initialized with the values from the specified metadata object.
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
      *
      * @param object The metadata to copy values from, or {@code null} if none.
-     *
-     * @see #castOrCopy(AssociatedResource)
      */
-    public DefaultAssociatedResource(final AssociatedResource object) {
+    DefaultAssociatedResource(final AggregateInformation object) {
         if (object != null) {
-            this.name              = object.getName();
             this.associationType   = object.getAssociationType();
             this.initiativeType    = object.getInitiativeType();
-            this.metadataReference = object.getMetadataReference();
+            if (object instanceof DefaultAssociatedResource) {
+                this.name              = ((DefaultAssociatedResource) object).getName();
+                this.metadataReference = ((DefaultAssociatedResource) object).getMetadataReference();
+            }
         }
     }
 
     /**
      * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultAssociatedResource}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultAssociatedResource} instance is created using the
-     *       {@linkplain #DefaultAssociatedResource(AssociatedResource) copy constructor} and returned.
-     *       Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
      *
      * @param  object The object to get as a SIS implementation, or {@code null} if none.
      * @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 DefaultAssociatedResource castOrCopy(final AssociatedResource object) {
+    static DefaultAssociatedResource castOrCopy(final AggregateInformation object) {
         if (object == null || object instanceof DefaultAssociatedResource) {
             return (DefaultAssociatedResource) object;
         }
@@ -146,8 +156,8 @@
      *
      * @return Citation information about the associated resource, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "name")
+    @UML(identifier="name", obligation=CONDITIONAL, specification=ISO_19115)
     public Citation getName() {
         return name;
     }
@@ -167,8 +177,8 @@
      *
      * @return Type of relation between the resources.
      */
-    @Override
 /// @XmlElement(name = "associationType", required = true)
+    @UML(identifier="associationType", obligation=MANDATORY, specification=ISO_19115)
     public AssociationType getAssociationType() {
         return associationType;
     }
@@ -188,8 +198,8 @@
      *
      * @return The type of initiative under which the associated resource was produced, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "initiativeType")
+    @UML(identifier="initiativeType", obligation=OPTIONAL, specification=ISO_19115)
     public InitiativeType getInitiativeType() {
         return initiativeType;
     }
@@ -209,8 +219,8 @@
      *
      * @return Reference to the metadata of the associated resource, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "metadataReference")
+    @UML(identifier="metadataReference", obligation=CONDITIONAL, specification=ISO_19115)
     public Citation getMetadataReference() {
         return metadataReference;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
index 475bf47..a8d11ad 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
@@ -22,6 +22,7 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.constraint.Constraints;
@@ -29,6 +30,9 @@
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.gmx.MimeFileTypeAdapter;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Graphic that provides an illustration of the dataset (should include a legend for the graphic).
@@ -118,8 +122,10 @@
             fileName         = object.getFileName();
             fileDescription  = object.getFileDescription();
             fileType         = object.getFileType();
-            imageConstraints = object.getImageConstraints();
-            linkages         = object.getLinkages();
+            if (object instanceof DefaultBrowseGraphic) {
+                imageConstraints = ((DefaultBrowseGraphic) object).getImageConstraints();
+                linkages         = ((DefaultBrowseGraphic) object).getLinkages();
+            }
         }
     }
 
@@ -225,8 +231,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "imageConstraints")
+    @UML(identifier="imageContraints", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Constraints> getImageConstraints() {
         return imageConstraints = nonNullCollection(imageConstraints, Constraints.class);
     }
@@ -249,8 +255,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "linkage")
+    @UML(identifier="linkage", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<OnlineResource> getLinkages() {
         return linkages = nonNullCollection(linkages, OnlineResource.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
index 11fb413..b005cce 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
@@ -25,18 +25,29 @@
 import org.opengis.util.ScopedName;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.identification.DataIdentification;
-import org.opengis.metadata.identification.CoupledResource;
-import org.opengis.metadata.identification.OperationMetadata;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.metadata.direct.GO_ScopedName;
 import org.apache.sis.xml.Namespaces;
 
 import static org.apache.sis.internal.jaxb.gco.PropertyType.LEGACY_XML;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Links a given operation name with a resource identified by an "identifier".
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code CoupledResource} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -61,7 +72,8 @@
     "operation" */
 })
 @XmlRootElement(name = "SV_CoupledResource", namespace = Namespaces.SRV)
-public class DefaultCoupledResource extends ISOMetadata implements CoupledResource {
+@UML(identifier="SV_CoupledResource", specification=ISO_19115)
+public class DefaultCoupledResource extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -85,7 +97,7 @@
     /**
      * The service operation.
      */
-    private OperationMetadata operation;
+    private DefaultOperationMetadata operation;
 
     /**
      * Constructs an initially empty coupled resource.
@@ -104,7 +116,7 @@
     public DefaultCoupledResource(final ScopedName name,
                                   final Citation reference,
                                   final DataIdentification resource,
-                                  final OperationMetadata operation)
+                                  final DefaultOperationMetadata operation)
     {
         this.scopedName         = name;
         this.resourceReferences = singleton(reference, Citation.class);
@@ -121,7 +133,7 @@
      *
      * @see #castOrCopy(CoupledResource)
      */
-    public DefaultCoupledResource(final CoupledResource object) {
+    public DefaultCoupledResource(final DefaultCoupledResource object) {
         super(object);
         if (object != null) {
             this.scopedName         = object.getScopedName();
@@ -132,38 +144,13 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultCoupledResource}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultCoupledResource} instance is created using the
-     *       {@linkplain #DefaultCoupledResource(CoupledResource) copy constructor} and returned.
-     *       Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultCoupledResource castOrCopy(final CoupledResource object) {
-        if (object == null || object instanceof DefaultCoupledResource) {
-            return (DefaultCoupledResource) object;
-        }
-        return new DefaultCoupledResource(object);
-    }
-
-    /**
      * Returns scoped identifier of the resource in the context of the given service instance.
      *
      * @return identifier of the resource, or {@code null} if none.
      */
-    @Override
     @XmlElementRef
     @XmlJavaTypeAdapter(GO_ScopedName.class)
+    @UML(identifier="scopedName", obligation=OPTIONAL, specification=ISO_19115)
     public ScopedName getScopedName() {
         return scopedName;
     }
@@ -183,8 +170,8 @@
      *
      * @return References to the resource on which the services operates.
      */
-    @Override
 /// @XmlElement(name = "resourceReference", namespace = Namespaces.SRV)
+    @UML(identifier="resourceReference", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getResourceReferences() {
         return resourceReferences = nonNullCollection(resourceReferences, Citation.class);
     }
@@ -203,8 +190,8 @@
      *
      * @return tightly coupled resources.
      */
-    @Override
 /// @XmlElement(name = "resource", namespace = Namespaces.SRV)
+    @UML(identifier="resource", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<DataIdentification> getResources() {
         return resources = nonNullCollection(resources, DataIdentification.class);
     }
@@ -221,20 +208,30 @@
     /**
      * Returns the service operation.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The return type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return The service operation, or {@code null} if none.
      */
-    @Override
 /// @XmlElement(name = "operation", namespace = Namespaces.SRV)
-    public OperationMetadata getOperation() {
+    @UML(identifier="operation", obligation=OPTIONAL, specification=ISO_19115)
+    public DefaultOperationMetadata getOperation() {
         return operation;
     }
 
     /**
      * Sets a new service operation.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The argument type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValue The new service operation.
      */
-    public void setOperation(final OperationMetadata newValue) {
+    public void setOperation(final DefaultOperationMetadata newValue) {
         checkWritePermission();
         this.operation = newValue;
     }
@@ -259,7 +256,7 @@
     @XmlElement(name = "operationName", namespace = Namespaces.SRV)
     private String getOperationName() {
         if (LEGACY_XML) {
-            final OperationMetadata operation = getOperation();
+            final DefaultOperationMetadata operation = getOperation();
             if (operation != null) {
                 return operation.getOperationName();
             }
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 6322c7d..03ec288 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
@@ -24,6 +24,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.extent.Extent;
 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.opengis.util.InternationalString;
@@ -63,7 +64,7 @@
     /**
      * Serial number for compatibility with different versions.
      */
-    private static final long serialVersionUID = 6104637930243499851L;
+    private static final long serialVersionUID = 6104637930243499850L;
 
     /**
      * Language(s) used within the dataset.
@@ -73,7 +74,7 @@
     /**
      * Full name of the character coding standard used for the dataset.
      */
-    private Collection<Charset> characterSets;
+    private Collection<CharacterSet> characterSets;
 
     /**
      * Description of the dataset in the producer’s processing environment, including items
@@ -123,7 +124,7 @@
         super(object);
         if (object != null) {
             languages                  = copyCollection(object.getLanguages(), Locale.class);
-            characterSets              = copyCollection(object.getCharacterSets(), Charset.class);
+            characterSets              = copyCollection(object.getCharacterSets(), CharacterSet.class);
             environmentDescription     = object.getEnvironmentDescription();
             supplementalInformation    = object.getSupplementalInformation();
         }
@@ -184,21 +185,29 @@
     /**
      * 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.
      */
     @Override
     @XmlElement(name = "characterSet")
-    public Collection<Charset> getCharacterSets() {
-        return characterSets = nonNullCollection(characterSets, Charset.class);
+    public Collection<CharacterSet> getCharacterSets() {
+        return characterSets = nonNullCollection(characterSets, CharacterSet.class);
     }
 
     /**
      * 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.
      */
-    public void setCharacterSets(final Collection<? extends Charset> newValues) {
-        characterSets = writeCollection(newValues, characterSets, Charset.class);
+    public void setCharacterSets(final Collection<? extends CharacterSet> newValues) {
+        characterSets = writeCollection(newValues, characterSets, CharacterSet.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
index bd599de..337986a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
@@ -22,7 +22,6 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.KeywordClass;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
@@ -31,6 +30,14 @@
  * Specification of a class to categorize keywords in a domain-specific vocabulary
  * that has a binding to a formal ontology.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code KeywordClass} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -51,7 +58,7 @@
     "ontology"
 })
 @XmlRootElement(name = "MD_KeywordClass")
-public class DefaultKeywordClass extends ISOMetadata implements KeywordClass {
+public class DefaultKeywordClass extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -99,7 +106,7 @@
      *
      * @see #castOrCopy(KeywordClass)
      */
-    public DefaultKeywordClass(final KeywordClass object) {
+    public DefaultKeywordClass(final DefaultKeywordClass object) {
         super(object);
         if (object != null) {
             className         = object.getClassName();
@@ -109,36 +116,10 @@
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultKeywordClass}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultKeywordClass} instance is created using the
-     *       {@linkplain #DefaultKeywordClass(KeywordClass) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultKeywordClass castOrCopy(final KeywordClass object) {
-        if (object == null || object instanceof DefaultKeywordClass) {
-            return (DefaultKeywordClass) object;
-        }
-        return new DefaultKeywordClass(object);
-    }
-
-    /**
      * Returns a label for the keyword category in natural language.
      *
      * @return The keyword category in natural language.
      */
-    @Override
     @XmlElement(name = "className", required = true)
     public InternationalString getClassName() {
         return className;
@@ -159,7 +140,6 @@
      *
      * @return URI of concept in the ontology, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "conceptIdentifier")
     public URI getConceptIdentifier() {
         return conceptIdentifier;
@@ -180,7 +160,6 @@
      *
      * @return A reference that binds the keyword class to a formal conceptualization.
      */
-    @Override
     @XmlElement(name = "ontology", required = true)
     public Citation getOntology() {
         return ontology;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
index 41ede4d..5f81042 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
@@ -20,14 +20,18 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.util.CodeList;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.identification.Keywords;
 import org.opengis.metadata.identification.KeywordType;
-import org.opengis.metadata.identification.KeywordClass;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Keywords, their type and reference source.
@@ -79,7 +83,7 @@
      * User-defined categorization of groups of keywords that extend or are orthogonal
      * to the standardized {@linkplain #getType() keyword type} codes.
      */
-    private KeywordClass keywordClass;
+    private CodeList<?> keywordClass;
 
     /**
      * Constructs an initially empty keywords.
@@ -216,23 +220,57 @@
      * Returns the user-defined categorization of groups of keywords that extend or
      * are orthogonal to the standardized {@linkplain #getType() keyword type} codes.
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The element type will be changed to the {@code KeywordClass} code list
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return User-defined categorization of groups of keywords, or {@code null} if none.
      *
      * @since 0.5
      */
-    @Override
-    public KeywordClass getKeywordClass() {
+    @UML(identifier="keywordClass", obligation=OPTIONAL, specification=ISO_19115)
+    public CodeList<?> getKeywordClass() {
         return keywordClass;
     }
 
     /**
      * Sets the user-defined categorization of groups of keywords.
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The argument type will be changed to the {@code KeywordClass} code list when GeoAPI will provide it
+     * (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
+     *
+     * {@preformat java
+     *   final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+     *       private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+     *
+     *       // Need to declare at least one code list element.
+     *       public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
+     *
+     *       private UnsupportedCodeList(String name) {
+     *           super(name, VALUES);
+     *       }
+     *
+     *       public static UnsupportedCodeList valueOf(String code) {
+     *           return valueOf(UnsupportedCodeList.class, code);
+     *       }
+     *
+     *       &#64;Override
+     *       public UnsupportedCodeList[] family() {
+     *           synchronized (VALUES) {
+     *               return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+     *           }
+     *       }
+     *   }
+     * }
+     * </div>
+     *
      * @param newValue New user-defined categorization of groups of keywords.
      *
      * @since 0.5
      */
-    public void setKeywordClass(final KeywordClass newValue) {
+    public void setKeywordClass(final CodeList<?> newValue) {
         checkWritePermission();
         keywordClass = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
index dbd6f70..e2e5de6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
@@ -20,17 +20,29 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.identification.OperationChainMetadata;
-import org.opengis.metadata.identification.OperationMetadata;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
+// Branch-specific imports
+import org.opengis.annotation.UML;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Operation chain information.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code OperationChainMetadata} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -52,11 +64,12 @@
     "operations"
 })
 @XmlRootElement(name = "SV_OperationChainMetadata", namespace = Namespaces.SRV)
-public class DefaultOperationChainMetadata extends ISOMetadata implements OperationChainMetadata {
+@UML(identifier="SV_OperationChainMetadata", specification=ISO_19115)
+public class DefaultOperationChainMetadata extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
-    private static final long serialVersionUID = 4132508877114835287L;
+    private static final long serialVersionUID = 4132508877114835286L;
 
     /**
      * The name as used by the service for this chain.
@@ -71,7 +84,7 @@
     /**
      * Information about the operations applied by the chain.
      */
-    private List<OperationMetadata> operations;
+    private List<DefaultOperationMetadata> operations;
 
     /**
      * Constructs an initially empty operation chain metadata.
@@ -97,47 +110,22 @@
      *
      * @see #castOrCopy(OperationChainMetadata)
      */
-    public DefaultOperationChainMetadata(final OperationChainMetadata object) {
+    public DefaultOperationChainMetadata(final DefaultOperationChainMetadata object) {
         super(object);
         if (object != null) {
             this.name        = object.getName();
             this.description = object.getDescription();
-            this.operations  = copyList(object.getOperations(), OperationMetadata.class);
+            this.operations  = copyList(object.getOperations(), DefaultOperationMetadata.class);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultOperationChainMetadata}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultOperationChainMetadata} instance is created using the
-     *       {@linkplain #DefaultOperationChainMetadata(OperationChainMetadata) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultOperationChainMetadata castOrCopy(final OperationChainMetadata object) {
-        if (object == null || object instanceof DefaultOperationChainMetadata) {
-            return (DefaultOperationChainMetadata) object;
-        }
-        return new DefaultOperationChainMetadata(object);
-    }
-
-    /**
      * Returns the name as used by the service for this chain.
      *
      * @return Name as used by the service for this chain.
      */
-    @Override
     @XmlElement(name = "name", namespace = Namespaces.SRV, required = true)
+    @UML(identifier="name", obligation=MANDATORY, specification=ISO_19115)
     public InternationalString getName() {
         return name;
     }
@@ -157,8 +145,8 @@
      *
      * @return Narrative explanation of the services in the chain and resulting output, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "description", namespace = Namespaces.SRV)
+    @UML(identifier="description", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDescription() {
         return description;
     }
@@ -176,20 +164,30 @@
     /**
      * Returns information about the operations applied by the chain.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information about the operations applied by the chain.
      */
-    @Override
     @XmlElement(name = "operation", namespace = Namespaces.SRV, required = true)
-    public List<OperationMetadata> getOperations() {
-        return operations = nonNullList(operations, OperationMetadata.class);
+    @UML(identifier="operation", obligation=MANDATORY, specification=ISO_19115)
+    public List<DefaultOperationMetadata> getOperations() {
+        return operations = nonNullList(operations, DefaultOperationMetadata.class);
     }
 
     /**
      * Sets the information about the operations applied by the chain.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new information about the operations applied by the chain.
      */
-    public void setOperations(final List<? extends OperationMetadata> newValues) {
-        operations = writeList(newValues, operations, OperationMetadata.class);
+    public void setOperations(final List<? extends DefaultOperationMetadata> newValues) {
+        operations = writeList(newValues, operations, DefaultOperationMetadata.class);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
index 8775755..09a571e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
@@ -21,18 +21,33 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.identification.DistributedComputingPlatform;
-import org.opengis.metadata.identification.OperationMetadata;
 import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.xml.Namespaces;
 
+// Branch-specific imports
+import org.opengis.util.CodeList;
+import org.opengis.annotation.UML;
+import org.apache.sis.internal.jaxb.code.DCPList;
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Parameter information.
  *
+ * <div class="warning"><b>Note on International Standard versions</b><br>
+ * This class is derived from a new type defined in the ISO 19115 international standard published in 2014,
+ * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does
+ * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases.
+ * When the interface will become available, all references to this implementation class in Apache SIS will
+ * be replaced be references to the {@code OperationMetadata} interface.
+ * </div>
+ *
  * <p><b>Limitations:</b></p>
  * <ul>
  *   <li>Instances of this class are not synchronized for multi-threading.
@@ -58,11 +73,12 @@
     "dependsOn"
 })
 @XmlRootElement(name = "SV_OperationMetadata", namespace = Namespaces.SRV)
-public class DefaultOperationMetadata extends ISOMetadata implements OperationMetadata {
+@UML(identifier="SV_OperationMetadata", specification=ISO_19115)
+public class DefaultOperationMetadata extends ISOMetadata {
     /**
      * Serial number for compatibility with different versions.
      */
-    private static final long serialVersionUID = -6120853428175790473L;
+    private static final long serialVersionUID = -3513177609655567627L;
 
     /**
      * An unique identifier for this interface.
@@ -72,7 +88,7 @@
     /**
      * Distributed computing platforms on which the operation has been implemented.
      */
-    private Collection<DistributedComputingPlatform> distributedComputingPlatforms;
+    private Collection<CodeList<?>> distributedComputingPlatforms;
 
     /**
      * Free text description of the intent of the operation and the results of the operation.
@@ -97,7 +113,7 @@
     /**
      * List of operation that must be completed immediately.
      */
-    private List<OperationMetadata> dependsOn;
+    private List<DefaultOperationMetadata> dependsOn;
 
     /**
      * Constructs an initially empty operation metadata.
@@ -106,22 +122,6 @@
     }
 
     /**
-     * Constructs a new operation metadata initialized to the specified values.
-     *
-     * @param operationName An unique identifier for this interface.
-     * @param platform      Distributed computing platforms on which the operation has been implemented.
-     * @param connectPoint  Handle for accessing the service interface.
-     */
-    public DefaultOperationMetadata(final String operationName,
-                                    final DistributedComputingPlatform platform,
-                                    final OnlineResource connectPoint)
-    {
-        this.operationName                 = operationName;
-        this.distributedComputingPlatforms = singleton(platform, DistributedComputingPlatform.class);
-        this.connectPoints                 = singleton(connectPoint, OnlineResource.class);
-    }
-
-    /**
      * Constructs a new instance initialized with the values from the specified metadata object.
      * This is a <cite>shallow</cite> copy constructor, since the other metadata contained in the
      * given object are not recursively copied.
@@ -131,51 +131,26 @@
      * @see #castOrCopy(OperationMetadata)
      */
     @SuppressWarnings("unchecked")
-    public DefaultOperationMetadata(final OperationMetadata object) {
+    public DefaultOperationMetadata(final DefaultOperationMetadata object) {
         super(object);
         if (object != null) {
             this.operationName                 = object.getOperationName();
-            this.distributedComputingPlatforms = copyCollection(object.getDistributedComputingPlatforms(), DistributedComputingPlatform.class);
+            this.distributedComputingPlatforms = copyCollection(object.getDistributedComputingPlatforms(), (Class) CodeList.class);
             this.operationDescription          = object.getOperationDescription();
             this.invocationName                = object.getInvocationName();
             this.connectPoints                 = copyCollection(object.getConnectPoints(), OnlineResource.class);
             this.parameters                    = copySet(object.getParameters(), (Class) ParameterDescriptor.class);
-            this.dependsOn                     = copyList(object.getDependsOn(), OperationMetadata.class);
+            this.dependsOn                     = copyList(object.getDependsOn(), DefaultOperationMetadata.class);
         }
     }
 
     /**
-     * Returns a SIS metadata implementation with the values of the given arbitrary implementation.
-     * This method performs the first applicable action in the following choices:
-     *
-     * <ul>
-     *   <li>If the given object is {@code null}, then this method returns {@code null}.</li>
-     *   <li>Otherwise if the given object is already an instance of
-     *       {@code DefaultOperationMetadata}, then it is returned unchanged.</li>
-     *   <li>Otherwise a new {@code DefaultOperationMetadata} instance is created using the
-     *       {@linkplain #DefaultOperationMetadata(OperationMetadata) copy constructor}
-     *       and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
-     *       metadata contained in the given object are not recursively copied.</li>
-     * </ul>
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultOperationMetadata castOrCopy(final OperationMetadata object) {
-        if (object == null || object instanceof DefaultOperationMetadata) {
-            return (DefaultOperationMetadata) object;
-        }
-        return new DefaultOperationMetadata(object);
-    }
-
-    /**
      * Returns an unique identifier for this interface.
      *
      * @return An unique identifier for this interface.
      */
-    @Override
     @XmlElement(name = "operationName", namespace = Namespaces.SRV, required = true)
+    @UML(identifier="operationName", obligation=MANDATORY, specification=ISO_19115)
     public String getOperationName() {
         return operationName;
     }
@@ -193,21 +168,56 @@
     /**
      * Returns the distributed computing platforms (DCPs) on which the operation has been implemented.
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The element type will be changed to the {@code DistributedComputingPlatform} code list
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Distributed computing platforms on which the operation has been implemented.
      */
-    @Override
+    @XmlJavaTypeAdapter(DCPList.class)
     @XmlElement(name = "DCP", namespace = Namespaces.SRV, required = true)
-    public Collection<DistributedComputingPlatform> getDistributedComputingPlatforms() {
-        return distributedComputingPlatforms = nonNullCollection(distributedComputingPlatforms, DistributedComputingPlatform.class);
+    @UML(identifier="distributedComputingPlatform", obligation=MANDATORY, specification=ISO_19115)
+    public Collection<CodeList<?>> getDistributedComputingPlatforms() {
+        return distributedComputingPlatforms = nonNullCollection(distributedComputingPlatforms, (Class) CodeList.class);
     }
 
     /**
      * Sets the distributed computing platforms on which the operation has been implemented.
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The element type will be changed to the {@code DistributedComputingPlatform} code list when GeoAPI will provide
+     * it (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
+     *
+     * {@preformat java
+     *   final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+     *       private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+     *
+     *       // Need to declare at least one code list element.
+     *       public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
+     *
+     *       private UnsupportedCodeList(String name) {
+     *           super(name, VALUES);
+     *       }
+     *
+     *       public static UnsupportedCodeList valueOf(String code) {
+     *           return valueOf(UnsupportedCodeList.class, code);
+     *       }
+     *
+     *       &#64;Override
+     *       public UnsupportedCodeList[] family() {
+     *           synchronized (VALUES) {
+     *               return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+     *           }
+     *       }
+     *   }
+     * }
+     * </div>
+     *
      * @param newValues The new distributed computing platforms on which the operation has been implemented.
      */
-    public void setDistributedComputingPlatforms(final Collection<? extends DistributedComputingPlatform> newValues) {
-        distributedComputingPlatforms = writeCollection(newValues, distributedComputingPlatforms, DistributedComputingPlatform.class);
+    public void setDistributedComputingPlatforms(final Collection<? extends CodeList<?>> newValues) {
+        distributedComputingPlatforms = writeCollection(newValues, distributedComputingPlatforms, (Class) CodeList.class);
     }
 
     /**
@@ -215,8 +225,8 @@
      *
      * @return Free text description of the intent of the operation and the results of the operation, or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "operationDescription", namespace = Namespaces.SRV)
+    @UML(identifier="operationDescription", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getOperationDescription() {
         return operationDescription;
     }
@@ -237,8 +247,8 @@
      * @return The name used to invoke this interface within the context of the distributed computing platforms,
      *         or {@code null} if none.
      */
-    @Override
     @XmlElement(name = "invocationName", namespace = Namespaces.SRV)
+    @UML(identifier="invocationName", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getInvocationName() {
         return invocationName;
     }
@@ -258,8 +268,8 @@
      *
      * @return Handle for accessing the service interface.
      */
-    @Override
     @XmlElement(name = "connectPoint", namespace = Namespaces.SRV, required = true)
+    @UML(identifier="connectPoint", obligation=MANDATORY, specification=ISO_19115)
     public Collection<OnlineResource> getConnectPoints() {
         return connectPoints = nonNullCollection(connectPoints, OnlineResource.class);
     }
@@ -278,9 +288,9 @@
      *
      * @return The parameters that are required for this interface, or an empty collection if none.
      */
-    @Override
     @SuppressWarnings("unchecked")
     @XmlElement(name = "parameters", namespace = Namespaces.SRV)
+    @UML(identifier="parameters", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<ParameterDescriptor<?>> getParameters() {
         return parameters = nonNullCollection(parameters, (Class) ParameterDescriptor.class);
     }
@@ -298,20 +308,30 @@
     /**
      * Returns the list of operation that must be completed immediately before current operation is invoked.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return List of operation that must be completed immediately, or an empty list if none.
      */
-    @Override
     @XmlElement(name = "dependsOn", namespace = Namespaces.SRV)
-    public List<OperationMetadata> getDependsOn() {
-        return dependsOn = nonNullList(dependsOn, OperationMetadata.class);
+    @UML(identifier="dependsOn", obligation=OPTIONAL, specification=ISO_19115)
+    public List<DefaultOperationMetadata> getDependsOn() {
+        return dependsOn = nonNullList(dependsOn, DefaultOperationMetadata.class);
     }
 
     /**
      * Sets the list of operation that must be completed before current operation is invoked.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new list of operation.
      */
-    public void setDependsOn(final List<? extends OperationMetadata> newValues) {
-        dependsOn = writeList(newValues, dependsOn, OperationMetadata.class);
+    public void setDependsOn(final List<? extends DefaultOperationMetadata> newValues) {
+        dependsOn = writeList(newValues, dependsOn, DefaultOperationMetadata.class);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
index acc7a32..951497a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
@@ -20,6 +20,7 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.identification.RepresentativeFraction;
 import org.opengis.metadata.identification.Resolution;
@@ -31,6 +32,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Level of detail expressed as a scale factor or a ground distance.
@@ -155,13 +160,13 @@
         super(object);
         if (object != null) {
             for (byte p=SCALE; p<=TEXT; p++) {
-                final Object c;
+                Object c = null;
                 switch (p) {
                     case SCALE:    c = object.getEquivalentScale(); break;
-                    case DISTANCE: c = object.getDistance();        break;
-                    case VERTICAL: c = object.getVertical();        break;
-                    case ANGULAR:  c = object.getAngularDistance(); break;
-                    case TEXT:     c = object.getLevelOfDetail();   break;
+                    case DISTANCE: c = object.getDistance(); break;
+                    case VERTICAL: if (c instanceof DefaultResolution) c = ((DefaultResolution) object).getVertical(); break;
+                    case ANGULAR:  if (c instanceof DefaultResolution) c = ((DefaultResolution) object).getAngularDistance(); break;
+                    case TEXT:     if (c instanceof DefaultResolution) c = ((DefaultResolution) object).getLevelOfDetail(); break;
                     default:       throw new AssertionError(p);
                 }
                 if (c != null) {
@@ -278,7 +283,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="vertical", obligation=CONDITIONAL, specification=ISO_19115)
     @ValueRange(minimum=0, isMinIncluded=false)
     public Double getVertical() {
         return (property == VERTICAL) ? (Double) value : null;
@@ -309,7 +314,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="angularDistance", obligation=CONDITIONAL, specification=ISO_19115)
     @ValueRange(minimum=0, isMinIncluded=false)
     public Double getAngularDistance() {
         return (property == ANGULAR) ? (Double) value : null;
@@ -340,7 +345,7 @@
      *
      * @since 0.5
      */
-    @Override
+    @UML(identifier="levelOfDetail", obligation=CONDITIONAL, specification=ISO_19115)
     public InternationalString getLevelOfDetail() {
         return (property == TEXT) ? (InternationalString) value : null;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
index 01cbad4..022fe3c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
@@ -21,17 +21,22 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.annotation.UML;
+import org.opengis.util.CodeList;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.identification.DataIdentification;
 import org.opengis.metadata.distribution.StandardOrderProcess;
 import org.opengis.metadata.identification.ServiceIdentification;
-import org.opengis.metadata.identification.CoupledResource;
-import org.opengis.metadata.identification.CouplingType;
-import org.opengis.metadata.identification.OperationChainMetadata;
-import org.opengis.metadata.identification.OperationMetadata;
+import org.apache.sis.internal.jaxb.code.SV_CouplingType;
 import org.apache.sis.xml.Namespaces;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.MANDATORY;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Identification of capabilities which a service provider makes available to a service user
@@ -92,12 +97,12 @@
     /**
      * Type of coupling between service and associated data (if exist).
      */
-    private CouplingType couplingType;
+    private CodeList<?> couplingType;
 
     /**
      * Further description of the data coupling in the case of tightly coupled services.
      */
-    private Collection<CoupledResource> coupledResources;
+    private Collection<DefaultCoupledResource> coupledResources;
 
     /**
      * References to the resource on which the service operates.
@@ -117,7 +122,7 @@
     /**
      * Information about the operations that comprise the service.
      */
-    private Collection<OperationMetadata> containsOperations;
+    private Collection<DefaultOperationMetadata> containsOperations;
 
     /**
      * Information on the resources that the service operates on.
@@ -127,7 +132,7 @@
     /**
      * Information about the chain applied by the service.
      */
-    private Collection<OperationChainMetadata> containsChain;
+    private Collection<DefaultOperationChainMetadata> containsChain;
 
     /**
      * Constructs an initially empty service identification.
@@ -161,18 +166,19 @@
      */
     public DefaultServiceIdentification(final ServiceIdentification object) {
         super(object);
-        if (object != null) {
-            serviceType         = object.getServiceType();
-            serviceTypeVersions = copyCollection(object.getServiceTypeVersions(), String.class);
-            accessProperties    = object.getAccessProperties();
-            couplingType        = object.getCouplingType();
-            coupledResources    = copyCollection(object.getCoupledResources(), CoupledResource.class);
-            operatedDatasets    = copyCollection(object.getOperatedDatasets(), Citation.class);
-            profiles            = copyCollection(object.getProfiles(), Citation.class);
-            serviceStandards    = copyCollection(object.getServiceStandards(), Citation.class);
-            containsOperations  = copyCollection(object.getContainsOperations(), OperationMetadata.class);
-            operatesOn          = copyCollection(object.getOperatesOn(), DataIdentification.class);
-            containsChain       = copyCollection(object.getContainsChain(), OperationChainMetadata.class);
+        if (object instanceof DefaultServiceIdentification) {
+            final DefaultServiceIdentification c = (DefaultServiceIdentification) object;
+            serviceType         = c.getServiceType();
+            serviceTypeVersions = copyCollection(c.getServiceTypeVersions(), String.class);
+            accessProperties    = c.getAccessProperties();
+            couplingType        = c.getCouplingType();
+            coupledResources    = copyCollection(c.getCoupledResources(), DefaultCoupledResource.class);
+            operatedDatasets    = copyCollection(c.getOperatedDatasets(), Citation.class);
+            profiles            = copyCollection(c.getProfiles(), Citation.class);
+            serviceStandards    = copyCollection(c.getServiceStandards(), Citation.class);
+            containsOperations  = copyCollection(c.getContainsOperations(), DefaultOperationMetadata.class);
+            operatesOn          = copyCollection(c.getOperatesOn(), DataIdentification.class);
+            containsChain       = copyCollection(c.getContainsChain(), DefaultOperationChainMetadata.class);
         }
     }
 
@@ -208,8 +214,8 @@
      *
      * @return A service type name.
      */
-    @Override
     @XmlElement(name = "serviceType", namespace = Namespaces.SRV, required = true)
+    @UML(identifier="serviceType", obligation=MANDATORY, specification=ISO_19115)
     public GenericName getServiceType() {
         return serviceType;
     }
@@ -229,8 +235,8 @@
      *
      * @return The versions of the service.
      */
-    @Override
     @XmlElement(name = "serviceTypeVersion", namespace = Namespaces.SRV)
+    @UML(identifier="serviceTypeVersion", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<String> getServiceTypeVersions() {
         return serviceTypeVersions = nonNullCollection(serviceTypeVersions, String.class);
     }
@@ -251,8 +257,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "accessProperties", namespace = Namespaces.SRV)
+    @UML(identifier="accessProperties", obligation=OPTIONAL, specification=ISO_19115)
     public StandardOrderProcess getAccessProperties() {
         return accessProperties;
 
@@ -273,20 +279,55 @@
     /**
      * Returns type of coupling between service and associated data (if exist).
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The return type will be changed to the {@code CouplingType} code list
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Type of coupling between service and associated data, or {@code null} if none.
      */
-    @Override
+    @XmlJavaTypeAdapter(SV_CouplingType.class)
     @XmlElement(name = "couplingType", namespace = Namespaces.SRV)
-    public CouplingType getCouplingType() {
+    @UML(identifier="couplingType", obligation=CONDITIONAL, specification=ISO_19115)
+    public CodeList<?> getCouplingType() {
         return couplingType;
     }
 
     /**
      * Sets the type of coupling between service and associated data.
      *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The argument type will be changed to the {@code CouplingType} code list when GeoAPI will provide it
+     * (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
+     *
+     * {@preformat java
+     *   final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+     *       private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+     *
+     *       // Need to declare at least one code list element.
+     *       public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
+     *
+     *       private UnsupportedCodeList(String name) {
+     *           super(name, VALUES);
+     *       }
+     *
+     *       public static UnsupportedCodeList valueOf(String code) {
+     *           return valueOf(UnsupportedCodeList.class, code);
+     *       }
+     *
+     *       &#64;Override
+     *       public UnsupportedCodeList[] family() {
+     *           synchronized (VALUES) {
+     *               return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+     *           }
+     *       }
+     *   }
+     * }
+     * </div>
+     *
      * @param newValue The new type of coupling between service and associated data.
      */
-    public void setCouplingType(final CouplingType newValue) {
+    public void setCouplingType(final CodeList<?> newValue) {
         checkWritePermission();
         couplingType = newValue;
     }
@@ -294,21 +335,31 @@
     /**
      * Returns further description(s) of the data coupling in the case of tightly coupled services.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code CoupledResource} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Further description(s) of the data coupling in the case of tightly coupled services.
      */
-    @Override
     @XmlElement(name = "coupledResource", namespace = Namespaces.SRV)
-    public Collection<CoupledResource> getCoupledResources() {
-        return coupledResources = nonNullCollection(coupledResources, CoupledResource.class);
+    @UML(identifier="coupledResource", obligation=CONDITIONAL, specification=ISO_19115)
+    public Collection<DefaultCoupledResource> getCoupledResources() {
+        return coupledResources = nonNullCollection(coupledResources, DefaultCoupledResource.class);
     }
 
     /**
      * Sets further description(s) of the data coupling in the case of tightly coupled services.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code CoupledResource} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new further description(s) of the data coupling.
      */
-    public void setCoupledResources(final Collection<? extends CoupledResource> newValues) {
-        coupledResources = writeCollection(newValues, coupledResources, CoupledResource.class);
+    public void setCoupledResources(final Collection<? extends DefaultCoupledResource> newValues) {
+        coupledResources = writeCollection(newValues, coupledResources, DefaultCoupledResource.class);
     }
 
     /**
@@ -318,8 +369,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "operatedDataset", namespace = Namespaces.SRV)
+    @UML(identifier="operatedDataset", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getOperatedDatasets() {
         return operatedDatasets = nonNullCollection(operatedDatasets, Citation.class);
     }
@@ -342,8 +393,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "profile", namespace = Namespaces.SRV)
+    @UML(identifier="profile", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getProfiles() {
         return profiles = nonNullCollection(profiles, Citation.class);
     }
@@ -364,8 +415,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "serviceStandard", namespace = Namespaces.SRV)
+    @UML(identifier="serviceStandard", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getServiceStandards() {
         return serviceStandards = nonNullCollection(serviceStandards, Citation.class);
     }
@@ -384,21 +435,31 @@
     /**
      * Provides information about the operations that comprise the service.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information about the operations that comprise the service.
      */
-    @Override
     @XmlElement(name = "containsOperations", namespace = Namespaces.SRV)
-    public Collection<OperationMetadata> getContainsOperations() {
-        return containsOperations = nonNullCollection(containsOperations, OperationMetadata.class);
+    @UML(identifier="containsOperations", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultOperationMetadata> getContainsOperations() {
+        return containsOperations = nonNullCollection(containsOperations, DefaultOperationMetadata.class);
     }
 
     /**
      * Sets information(s) about the operations that comprise the service.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new information(s) about the operations that comprise the service.
      */
-    public void setContainsOperations(final Collection<? extends OperationMetadata> newValues) {
-        containsOperations = writeCollection(newValues, containsOperations, OperationMetadata.class);
+    public void setContainsOperations(final Collection<? extends DefaultOperationMetadata> newValues) {
+        containsOperations = writeCollection(newValues, containsOperations, DefaultOperationMetadata.class);
     }
 
     /**
@@ -406,8 +467,8 @@
      *
      * @return Information on the resources that the service operates on.
      */
-    @Override
     @XmlElement(name = "operatesOn", namespace = Namespaces.SRV)
+    @UML(identifier="operatesOn", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<DataIdentification> getOperatesOn() {
         return operatesOn = nonNullCollection(operatesOn, DataIdentification.class);
     }
@@ -424,25 +485,35 @@
     /**
      * Provides information about the chain applied by the service.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationChainMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @return Information about the chain applied by the service.
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "containsChain", namespace = Namespaces.SRV)
-    public Collection<OperationChainMetadata> getContainsChain() {
-        return containsChain = nonNullCollection(containsChain, OperationChainMetadata.class);
+    @UML(identifier="containsChain", obligation=OPTIONAL, specification=ISO_19115)
+    public Collection<DefaultOperationChainMetadata> getContainsChain() {
+        return containsChain = nonNullCollection(containsChain, DefaultOperationChainMetadata.class);
     }
 
     /**
      * Sets the information about the chain applied by the service.
      *
+     * <div class="warning"><b>Upcoming API change — generalization</b><br>
+     * The element type will be changed to the {@code OperationChainMetadata} interface
+     * when GeoAPI will provide it (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param newValues The new information about the chain applied by the service.
      *
      * @since 0.5
      */
-    public void setContainsChain(final Collection<? extends OperationChainMetadata>  newValues) {
-        containsChain = writeCollection(newValues, containsChain, OperationChainMetadata.class);
+    public void setContainsChain(final Collection<? extends DefaultOperationChainMetadata>  newValues) {
+        containsChain = writeCollection(newValues, containsChain, DefaultOperationChainMetadata.class);
     }
 
 
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 564dd63..b330ef2 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
@@ -21,13 +21,16 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 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.metadata.iso.ISOMetadata;
 import org.apache.sis.util.iso.Types;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
 
@@ -87,7 +90,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.
@@ -118,10 +121,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);
     }
 
     /**
@@ -139,10 +142,13 @@
             specificUsage             = object.getSpecificUsage();
             usageDate                 = toMilliseconds(object.getUsageDate());
             userDeterminedLimitations = object.getUserDeterminedLimitations();
-            userContactInfo           = copyCollection(object.getUserContactInfo(), Responsibility.class);
-            responses                 = copyCollection(object.getResponses(), InternationalString.class);
-            additionalDocumentation   = copyCollection(object.getAdditionalDocumentation(), Citation.class);
-            identifiedIssues          = copyCollection(object.getIdentifiedIssues(), Citation.class);
+            userContactInfo           = copyCollection(object.getUserContactInfo(), ResponsibleParty.class);
+            if (object instanceof DefaultUsage) {
+                final DefaultUsage c = (DefaultUsage) object;
+                responses                 = copyCollection(c.getResponses(), InternationalString.class);
+                additionalDocumentation   = copyCollection(c.getAdditionalDocumentation(), Citation.class);
+                identifiedIssues          = copyCollection(c.getIdentifiedIssues(), Citation.class);
+            }
         }
     }
 
@@ -237,21 +243,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 {@link 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", required = true)
-    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 {@link 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);
     }
 
     /**
@@ -261,8 +277,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "response")
+    @UML(identifier="response", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<? extends InternationalString> getResponses() {
         return responses = nonNullCollection(responses, InternationalString.class);
     }
@@ -285,8 +301,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "additionalDocumentation")
+    @UML(identifier="additionalDocumentation", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getAdditionalDocumentation() {
         return additionalDocumentation = nonNullCollection(additionalDocumentation, Citation.class);
     }
@@ -310,8 +326,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "identifiedIssues")
+    @UML(identifier="identifiedIssues", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<? extends Citation> getIdentifiedIssues() {
         return identifiedIssues = nonNullCollection(identifiedIssues, Citation.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/OperationName.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/OperationName.java
index eec4366..0c9560d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/OperationName.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/OperationName.java
@@ -16,18 +16,9 @@
  */
 package org.apache.sis.metadata.iso.identification;
 
-import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Collection;
-import java.util.Collections;
-import java.io.Serializable;
-import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.identification.CoupledResource;
-import org.opengis.metadata.identification.DistributedComputingPlatform;
-import org.opengis.metadata.identification.OperationMetadata;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.util.InternationalString;
 
 
 /**
@@ -39,41 +30,25 @@
  * @since   0.5
  * @module
  */
-final class OperationName implements OperationMetadata, Serializable {
+final class OperationName extends DefaultOperationMetadata {
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -7958898214063034276L;
-
-    /**
-     * The operation name.
-     */
-    private final String operationName;
+    private static final long serialVersionUID = 7221543581387125873L;
 
     /**
      * Creates a new placeholder for the operation of the given name.
      */
     OperationName(final String operationName) {
-        this.operationName = operationName;
+        setOperationName(operationName);
     }
 
     /**
-     * Returns the operation name.
-     */
-    @Override public String                                   getOperationName()                 {return operationName;}
-    @Override public InternationalString                      getInvocationName()                {return null;}
-    @Override public InternationalString                      getOperationDescription()          {return null;}
-    @Override public Collection<DistributedComputingPlatform> getDistributedComputingPlatforms() {return Collections.emptySet();}
-    @Override public Collection<OnlineResource>               getConnectPoints()                 {return Collections.emptySet();}
-    @Override public Collection<ParameterDescriptor<?>>       getParameters()                    {return Collections.emptySet();}
-    @Override public List<OperationMetadata>                  getDependsOn()                     {return Collections.emptyList();}
-
-    /**
      * Returns a string representation of this placeholder.
      */
     @Override
     public String toString() {
-        return "OperationMetadata[“" + operationName + "”]";
+        return "OperationMetadata[“" + getOperationName() + "”]";
     }
 
     /**
@@ -86,25 +61,23 @@
      * <p>This method is invoked at unmarshalling time for resolving the {@code OperationMetadata} instance which
      * were identified only by a name in a {@code <srv:operationName>} element.</p>
      */
-    static void resolve(final Collection<OperationMetadata> containsOperations, final Collection<CoupledResource> coupledResources) {
-        final Map<String,OperationMetadata> byName = new HashMap<String,OperationMetadata>();
-        for (final OperationMetadata operation : containsOperations) {
+    static void resolve(final Collection<DefaultOperationMetadata> containsOperations, final Collection<DefaultCoupledResource> coupledResources) {
+        final Map<String,DefaultOperationMetadata> byName = new HashMap<String,DefaultOperationMetadata>();
+        for (final DefaultOperationMetadata operation : containsOperations) {
             add(byName, operation.getOperationName(), operation);
         }
-        for (final CoupledResource resource : coupledResources) {
-            if (resource instanceof DefaultCoupledResource) {
-                OperationMetadata operation = resource.getOperation();
-                if (operation instanceof OperationName) {
-                    final String name = operation.getOperationName();
+        for (final DefaultCoupledResource resource : coupledResources) {
+            DefaultOperationMetadata operation = resource.getOperation();
+            if (operation instanceof OperationName) {
+                final String name = operation.getOperationName();
+                operation = byName.get(name);
+                if (operation == null) {
                     operation = byName.get(name);
                     if (operation == null) {
-                        operation = byName.get(name);
-                        if (operation == null) {
-                            continue;
-                        }
+                        continue;
                     }
-                    ((DefaultCoupledResource) resource).setOperation(operation);
                 }
+                resource.setOperation(operation);
             }
         }
     }
@@ -113,9 +86,9 @@
      * Adds the given operation in the given map under the given name. If an entry already exists for the given name,
      * then this method sets the value to {@code null} for meaning that we have duplicated values for that name.
      */
-    private static void add(final Map<String,OperationMetadata> byName, final String name, final OperationMetadata operation) {
+    private static void add(final Map<String,DefaultOperationMetadata> byName, final String name, final DefaultOperationMetadata operation) {
         final boolean exists = byName.containsKey(name);
-        final OperationMetadata previous = byName.put(name, operation);
+        final DefaultOperationMetadata previous = byName.put(name, operation);
         if (previous != operation && (previous != null || exists)) {
             byName.put(name, null); // Mark the entry as duplicated.
         }
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 453ddd8..9032cf4 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
@@ -109,8 +109,7 @@
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
-    @XmlJavaTypeAdapter(DCPList.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(DS_AssociationTypeCode.class),
     @XmlJavaTypeAdapter(DS_InitiativeTypeCode.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
@@ -132,11 +131,9 @@
     @XmlJavaTypeAdapter(MD_TopicCategoryCode.class),
     @XmlJavaTypeAdapter(MD_Usage.class),
     @XmlJavaTypeAdapter(SV_CoupledResource.class),
-    @XmlJavaTypeAdapter(SV_CouplingType.class),
     @XmlJavaTypeAdapter(SV_OperationMetadata.class),
     @XmlJavaTypeAdapter(SV_OperationChainMetadata.class),
     @XmlJavaTypeAdapter(SV_Parameter.class),
-    @XmlJavaTypeAdapter(SV_ParameterDirection.class),
 
     // Java types, primitive types and basic OGC types handling
     @XmlJavaTypeAdapter(URIAdapter.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
index 2228c73..d7c9eb9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
@@ -20,9 +20,10 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.metadata.lineage.Source;
 import org.opengis.metadata.lineage.Lineage;
 import org.opengis.metadata.lineage.ProcessStep;
@@ -30,6 +31,9 @@
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the events or source data used in constructing the data specified by
@@ -117,10 +121,12 @@
         super(object);
         if (object != null) {
             statement               = object.getStatement();
-            scope                   = object.getScope();
-            additionalDocumentation = copyCollection(object.getAdditionalDocumentation(), Citation.class);
             processSteps            = copyCollection(object.getProcessSteps(), ProcessStep.class);
             sources                 = copyCollection(object.getSources(), Source.class);
+            if (object instanceof DefaultLineage) {
+                scope                   = ((DefaultLineage) object).getScope();
+                additionalDocumentation = copyCollection(((DefaultLineage) object).getAdditionalDocumentation(), Citation.class);
+            }
         }
     }
 
@@ -179,8 +185,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "scope")
+    @UML(identifier="scope", obligation=OPTIONAL, specification=ISO_19115)
     public Scope getScope() {
         return scope;
     }
@@ -204,8 +210,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "additionalDocumentation")
+    @UML(identifier="additionalDocumentation", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getAdditionalDocumentation() {
         return additionalDocumentation = nonNullCollection(additionalDocumentation, Citation.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 d0e364b..84867af 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
@@ -22,10 +22,11 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.metadata.lineage.Source;
 import org.opengis.metadata.lineage.Processing;
 import org.opengis.metadata.lineage.ProcessStep;
@@ -34,6 +35,8 @@
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
 
@@ -75,7 +78,7 @@
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -535020568951006598L;
+    private static final long serialVersionUID = -3511714360929580873L;
 
     /**
      * Description of the event, including related parameters or tolerances.
@@ -98,7 +101,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.
@@ -162,13 +165,15 @@
             description           = object.getDescription();
             rationale             = object.getRationale();
             date                  = toMilliseconds(object.getDate());
-            processors            = copyCollection(object.getProcessors(), Responsibility.class);
-            references            = copyCollection(object.getReferences(), Citation.class);
+            processors            = copyCollection(object.getProcessors(), ResponsibleParty.class);
             sources               = copyCollection(object.getSources(), Source.class);
-            scope                 = object.getScope();
             outputs               = copyCollection(object.getOutputs(), Source.class);
             processingInformation = object.getProcessingInformation();
             reports               = copyCollection(object.getReports(), ProcessStepReport.class);
+            if (object instanceof DefaultProcessStep) {
+                references = copyCollection(((DefaultProcessStep) object).getReferences(), Citation.class);
+                scope      = ((DefaultProcessStep) object).getScope();
+            }
         }
     }
 
@@ -264,22 +269,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 {@link 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 {@link 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);
     }
 
     /**
@@ -289,8 +304,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "reference")
+    @UML(identifier="reference", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getReferences() {
         return references = nonNullCollection(references, Citation.class);
     }
@@ -313,8 +328,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "scope")
+    @UML(identifier="scope", obligation=OPTIONAL, specification=ISO_19115)
     public Scope getScope() {
         return scope;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
index fef812b..a084f5e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
@@ -22,6 +22,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
@@ -31,7 +32,7 @@
 import org.opengis.metadata.lineage.ProcessStep;
 import org.opengis.metadata.identification.Resolution;
 import org.opengis.metadata.identification.RepresentativeFraction;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.referencing.ReferenceSystem;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.iso.maintenance.DefaultScope;
@@ -39,6 +40,10 @@
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.xml.Namespaces;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Obligation.CONDITIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the source data used in creating the data specified by the scope.
@@ -154,14 +159,19 @@
         super(object);
         if (object != null) {
             description             = object.getDescription();
-            sourceSpatialResolution = object.getSourceSpatialResolution();
             sourceReferenceSystem   = object.getSourceReferenceSystem();
             sourceCitation          = object.getSourceCitation();
-            sourceMetadata          = copyCollection(object.getSourceMetadata(), Citation.class);
-            scope                   = object.getScope();
             sourceSteps             = copyCollection(object.getSourceSteps(), ProcessStep.class);
             processedLevel          = object.getProcessedLevel();
             resolution              = object.getResolution();
+            if (object instanceof DefaultSource) {
+                sourceSpatialResolution = ((DefaultSource) object).getSourceSpatialResolution();
+                sourceMetadata          = copyCollection(((DefaultSource) object).getSourceMetadata(), Citation.class);
+                scope                   = ((DefaultSource) object).getScope();
+            } else {
+                setScaleDenominator(object.getScaleDenominator());
+                setSourceExtents(object.getSourceExtents());
+            }
         }
     }
 
@@ -218,8 +228,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "sourceSpatialResolution")
+    @UML(identifier="sourceSpatialResolution", obligation=OPTIONAL, specification=ISO_19115)
     public Resolution getSourceSpatialResolution() {
         return sourceSpatialResolution;
     }
@@ -332,8 +342,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "sourceMetadata")
+    @UML(identifier="sourceMetadata", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Citation> getSourceMetadata() {
         return sourceMetadata = nonNullCollection(sourceMetadata, Citation.class);
     }
@@ -357,8 +367,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "scope")
+    @UML(identifier="scope", obligation=CONDITIONAL, specification=ISO_19115)
     public Scope getScope() {
         return scope;
     }
@@ -393,7 +403,7 @@
                 scope = new DefaultScope(scope);
                 this.scope = scope;
             } else {
-                return Collections.unmodifiableCollection(scope.getExtents());
+                return Collections.singleton(scope.getExtent());
             }
         }
         return ((DefaultScope) scope).getExtents();
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 b30d5c2..743b301 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
@@ -78,7 +78,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(LE_Algorithm.class),
     @XmlJavaTypeAdapter(LE_NominalResolution.class),
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 baa3cc0..11c38bd 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
@@ -23,20 +23,24 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 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;
 import org.opengis.metadata.maintenance.ScopeDescription;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.temporal.PeriodDuration;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.metadata.iso.citation.DefaultCitationDate;
 import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Information about the scope and frequency of updating.
@@ -76,6 +80,11 @@
     private static final long serialVersionUID = -8736825706141936429L;
 
     /**
+     * New code list item defined in ISO 19115:2014.
+     */
+    private static final DateType NEXT_UPDATE = DateType.valueOf("NEXT_UPDATE");
+
+    /**
      * Frequency with which changes and additions are made to the resource after the
      * initial resource is completed.
      */
@@ -105,7 +114,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.
@@ -136,11 +145,18 @@
         super(object);
         if (object != null) {
             maintenanceAndUpdateFrequency   = object.getMaintenanceAndUpdateFrequency();
-            maintenanceDates                = copyCollection(object.getMaintenanceDates(), CitationDate.class);
             userDefinedMaintenanceFrequency = object.getUserDefinedMaintenanceFrequency();
-            maintenanceScopes               = copyCollection(object.getMaintenanceScopes(), Scope.class);
             maintenanceNotes                = copyCollection(object.getMaintenanceNotes(), InternationalString.class);
-            contacts                        = copyCollection(object.getContacts(), Responsibility.class);
+            if (object instanceof DefaultMaintenanceInformation) {
+                final DefaultMaintenanceInformation c = (DefaultMaintenanceInformation) object;
+                maintenanceDates                = copyCollection(c.getMaintenanceDates(), CitationDate.class);
+                maintenanceScopes               = copyCollection(c.getMaintenanceScopes(), Scope.class);
+                contacts                        = copyCollection(c.getContacts(), ResponsibleParty.class);
+            } else {
+                setDateOfNextUpdate(object.getDateOfNextUpdate());
+                setUpdateScopes(object.getUpdateScopes());
+                setUpdateScopeDescriptions(object.getUpdateScopeDescriptions());
+            }
         }
     }
 
@@ -199,8 +215,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "maintenanceDate", required = true)
+    @UML(identifier="maintenanceDate", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<CitationDate> getMaintenanceDates() {
         return maintenanceDates = nonNullCollection(maintenanceDates, CitationDate.class);
     }
@@ -223,8 +239,8 @@
      * @return Scheduled revision date, or {@code null}.
      *
      * @deprecated As of ISO 19115:2014, replaced by {@link #getMaintenanceDates()} in order to enable inclusion
-     *             of a {@link DateType} to describe the type of the date. Note that {@link DateType#NEXT_UPDATE}
-     *             was added to that code list.
+     *             of a {@link DateType} to describe the type of the date. The associated date type is
+     *             {@code DateType.valueOf("NEXT_UPDATE")}.
      */
     @Override
     @Deprecated
@@ -233,7 +249,7 @@
         final Collection<CitationDate> dates = getMaintenanceDates();
         if (dates != null) { // May be null on XML marshalling.
             for (final CitationDate date : dates) {
-                if (DateType.NEXT_UPDATE.equals(date.getDateType())) {
+                if (NEXT_UPDATE.equals(date.getDateType())) {
                     return date.getDate();
                 }
             }
@@ -255,7 +271,7 @@
             final Iterator<CitationDate> it = dates.iterator();
             while (it.hasNext()) {
                 final CitationDate date = it.next();
-                if (DateType.NEXT_UPDATE.equals(date.getDateType())) {
+                if (NEXT_UPDATE.equals(date.getDateType())) {
                     if (newValue == null) {
                         it.remove();
                         return;
@@ -267,7 +283,7 @@
             }
         }
         if (newValue != null) {
-            final CitationDate date = new DefaultCitationDate(newValue, DateType.NEXT_UPDATE);
+            final CitationDate date = new DefaultCitationDate(newValue, NEXT_UPDATE);
             if (dates != null) {
                 dates.add(date);
             } else {
@@ -305,8 +321,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "maintenanceScope")
+    @UML(identifier="maintenanceScope", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Scope> getMaintenanceScopes() {
         return maintenanceScopes = nonNullCollection(maintenanceScopes, Scope.class);
     }
@@ -449,23 +465,33 @@
      * 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 {@link 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 {@link 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/DefaultScope.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
index 6d81fcb..9118519 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
@@ -20,12 +20,17 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.UML;
 import org.opengis.metadata.extent.Extent;
-import org.opengis.metadata.maintenance.Scope;
+import org.opengis.metadata.quality.Scope;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.maintenance.ScopeDescription;
+import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 import org.apache.sis.metadata.iso.ISOMetadata;
 
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * The target resource and physical extent for which information is reported.
@@ -100,8 +105,12 @@
         super(object);
         if (object != null) {
             level            = object.getLevel();
-            extents          = copyCollection(object.getExtents(), Extent.class);
             levelDescription = copyCollection(object.getLevelDescription(), ScopeDescription.class);
+            if (object instanceof DefaultScope) {
+                extents = copyCollection(((DefaultScope) object).getExtents(), Extent.class);
+            } else {
+                extents = singleton(object.getExtent(), Extent.class);
+            }
         }
     }
 
@@ -158,8 +167,8 @@
      *
      * @since 0.5
      */
-    @Override
     @XmlElement(name = "extent")
+    @UML(identifier="extent", obligation=OPTIONAL, specification=ISO_19115)
     public Collection<Extent> getExtents() {
         return extents = nonNullCollection(extents, Extent.class);
     }
@@ -176,6 +185,33 @@
     }
 
     /**
+     * Information about the spatial, vertical and temporal extent of the data specified by the scope.
+     * This method fetches the value from the {@linkplain #getExtents() extents} collection.
+     *
+     * @return Information about the extent of the data, or {@code null}.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #getExtents()}.
+     */
+    @Override
+    @Deprecated
+    public Extent getExtent() {
+        return LegacyPropertyAdapter.getSingleton(getExtents(), Extent.class, null, DefaultScope.class, "getExtent");
+    }
+
+    /**
+     * Sets information about the spatial, vertical and temporal extent of the data specified by the scope.
+     * This method stores the value in the {@linkplain #setExtents(Collection) extents} collection.
+     *
+     * @param newValue The new extent.
+     *
+     * @deprecated As of ISO 19115:2014, replaced by {@link #setExtents(Collection)}.
+     */
+    @Deprecated
+    public void setExtent(final Extent newValue) {
+        setExtents(LegacyPropertyAdapter.asCollection(newValue));
+    }
+
+    /**
      * Returns detailed descriptions about the level of the data specified by the scope.
      *
      * @return Detailed description about the level of the data.
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 d057967..8c30340 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
@@ -33,6 +33,10 @@
 
 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.
@@ -105,12 +109,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;
@@ -144,23 +148,31 @@
         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;
                 }
             }
@@ -193,31 +205,33 @@
     }
 
     /**
-     * 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) {
-        assert ((CheckedContainer<?>) value).getElementType() == CharSequence.class;
-        return (Set<CharSequence>) value;
+    private static <E> Set<E> cast(final Object value, final Class<E> type) {
+        assert ((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<CharSequence>(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;
@@ -230,17 +244,17 @@
      * @param caller The caller method, for logging purpose.
      * @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);
     }
 
     /**
@@ -304,11 +318,15 @@
      * 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
-    public Set<CharSequence> getFeatures() {
-        return getProperty(FEATURES);
+    public Set<FeatureType> getFeatures() {
+        return getProperty(FeatureType.class, FEATURES);
     }
 
     /**
@@ -318,10 +336,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);
     }
 
     /**
@@ -337,11 +359,15 @@
      * 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
-    public Set<CharSequence> getAttributes() {
-        return getProperty(ATTRIBUTES);
+    public Set<AttributeType> getAttributes() {
+        return getProperty(AttributeType.class, ATTRIBUTES);
     }
 
     /**
@@ -351,10 +377,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);
     }
 
     /**
@@ -370,11 +400,15 @@
      * 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
-    public Set<CharSequence> getFeatureInstances() {
-        return getProperty(FEATURE_INSTANCES);
+    public Set<FeatureType> getFeatureInstances() {
+        return getProperty(FeatureType.class, FEATURE_INSTANCES);
     }
 
     /**
@@ -384,10 +418,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);
     }
 
     /**
@@ -403,11 +441,15 @@
      * 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
-    public Set<CharSequence> getAttributeInstances() {
-        return getProperty(ATTRIBUTE_INSTANCES);
+    public Set<AttributeType> getAttributeInstances() {
+        return getProperty(AttributeType.class, ATTRIBUTE_INSTANCES);
     }
 
     /**
@@ -417,21 +459,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;
     }
 
     /**
@@ -442,9 +492,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();
         if (newValue != null || property == OTHER) {
             warningOnOverwrite(OTHER);
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 45bac7e..e71b848 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
@@ -74,7 +74,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(EX_Extent.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(MD_MaintenanceFrequencyCode.class),
     @XmlJavaTypeAdapter(MD_MaintenanceInformation.class),
     @XmlJavaTypeAdapter(MD_ScopeCode.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 b7893be..6683554 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
@@ -42,8 +42,8 @@
  * {@code  ├─} {@linkplain org.apache.sis.metadata.iso.DefaultFeatureTypeList              Feature type list}<br>
  * {@code  └─} {@linkplain org.apache.sis.metadata.iso.DefaultIdentifier                   Identifier}<br>
  * {@linkplain org.opengis.util.CodeList Code list}<br>
- * {@code  ├─} {@linkplain org.opengis.metadata.Datatype     Data type}<br>
- * {@code  └─} {@linkplain org.opengis.annotation.Obligation Obligation}<br>
+ * {@code  ├─} {@linkplain org.opengis.metadata.Datatype   Data type}<br>
+ * {@code  └─} {@linkplain org.opengis.metadata.Obligation Obligation}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
  *                     {@linkplain org.apache.sis.metadata.iso.DefaultMetadata                     Metadata}<br>
  * {@code  ├─}         {@linkplain org.apache.sis.metadata.iso.DefaultMetadataScope                Metadata scope}<br>
@@ -52,7 +52,7 @@
  * {@code  ├─}         {@linkplain org.apache.sis.metadata.iso.DefaultMetadataExtensionInformation Metadata extension information}<br>
  * {@code  │   └─}     {@linkplain org.apache.sis.metadata.iso.DefaultExtendedElementInformation   Extended element information}<br>
  * {@code  │       ├─} {@linkplain org.opengis.metadata.Datatype                                   Data type} «code list»<br>
- * {@code  │       └─} {@linkplain org.opengis.annotation.Obligation                               Obligation} «code list»<br>
+ * {@code  │       └─} {@linkplain org.opengis.metadata.Obligation                                 Obligation} «code list»<br>
  * {@code  ├─}         {@linkplain org.apache.sis.metadata.iso.DefaultFeatureTypeList              Feature type list}<br>
  * {@code  └─}         {@linkplain org.apache.sis.metadata.iso.DefaultIdentifier                   Identifier}<br>
  * </td></tr></table>
@@ -97,11 +97,10 @@
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_Responsibility.class),
+    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(DQ_DataQuality.class),
     @XmlJavaTypeAdapter(MD_ApplicationSchemaInformation.class),
     @XmlJavaTypeAdapter(MD_CharacterSetCode.class),
-    @XmlJavaTypeAdapter(LegacyCharacterSet.class),
     @XmlJavaTypeAdapter(MD_Constraints.class),
     @XmlJavaTypeAdapter(MD_ContentInformation.class),
     @XmlJavaTypeAdapter(MD_DatatypeCode.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 83d0d50..5b67af6 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,7 +23,7 @@
 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.apache.sis.metadata.iso.ISOMetadata;
 
 
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 e2dfd0f..2f469d0 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
@@ -16,12 +16,9 @@
  */
 package org.apache.sis.metadata.iso.quality;
 
-import java.util.Collection;
 import javax.xml.bind.annotation.XmlTransient;
-import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.quality.Scope;
 import org.opengis.metadata.maintenance.ScopeCode;
-import org.apache.sis.internal.metadata.LegacyPropertyAdapter;
 
 
 /**
@@ -105,31 +102,4 @@
         }
         return new DefaultScope(object);
     }
-
-    /**
-     * Information about the spatial, vertical and temporal extent of the data specified by the scope.
-     * This method fetches the value from the {@linkplain #getExtents() extents} collection.
-     *
-     * @return Information about the extent of the data, or {@code null}.
-     *
-     * @deprecated As of ISO 19115:2014, replaced by {@link #getExtents()}.
-     */
-    @Override
-    @Deprecated
-    public Extent getExtent() {
-        return LegacyPropertyAdapter.getSingleton(getExtents(), Extent.class, null, DefaultScope.class, "getExtent");
-    }
-
-    /**
-     * Sets information about the spatial, vertical and temporal extent of the data specified by the scope.
-     * This method stores the value in the {@linkplain #setExtents(Collection) extents} collection.
-     *
-     * @param newValue The new extent.
-     *
-     * @deprecated As of ISO 19115:2014, replaced by {@link #setExtents(Collection)}.
-     */
-    @Deprecated
-    public void setExtent(final Extent newValue) {
-        setExtents(LegacyPropertyAdapter.asCollection(newValue));
-    }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
index c42e4b4..e3da636 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
@@ -20,6 +20,7 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.annotation.UML;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.spatial.Dimension;
 import org.opengis.metadata.spatial.DimensionNameType;
@@ -30,6 +31,10 @@
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.ensurePositive;
 
+// Branch-specific imports
+import static org.opengis.annotation.Obligation.OPTIONAL;
+import static org.opengis.annotation.Specification.ISO_19115;
+
 
 /**
  * Axis properties.
@@ -133,8 +138,10 @@
             dimensionName        = object.getDimensionName();
             dimensionSize        = object.getDimensionSize();
             resolution           = object.getResolution();
-            dimensionTitle       = object.getDimensionTitle();
-            dimensionDescription = object.getDimensionDescription();
+            if (object instanceof DefaultDimension) {
+                dimensionTitle       = ((DefaultDimension) object).getDimensionTitle();
+                dimensionDescription = ((DefaultDimension) object).getDimensionDescription();
+            }
         }
     }
 
@@ -245,8 +252,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "dimensionTitle")
+    @UML(identifier="dimensionTitle", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDimensionTitle() {
         return dimensionTitle;
     }
@@ -270,8 +277,8 @@
      *
      * @since 0.5
      */
-    @Override
 /// @XmlElement(name = "dimensionDescription")
+    @UML(identifier="dimensionDescription", obligation=OPTIONAL, specification=ISO_19115)
     public InternationalString getDimensionDescription() {
         return dimensionDescription;
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java
index 9265b99..8a3fc27 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java
@@ -24,7 +24,7 @@
 import org.opengis.metadata.citation.Role;
 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.citation.PresentationForm;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.internal.jaxb.Schemas;
@@ -85,7 +85,7 @@
     @Test
     public void testDefaultURL() throws JAXBException {
         final String expected = getResponsiblePartyXML(Schemas.METADATA_ROOT);
-        final Responsibility rp = (Responsibility) XML.unmarshal(expected);
+        final ResponsibleParty rp = (ResponsibleParty) XML.unmarshal(expected);
         assertEquals(Role.PRINCIPAL_INVESTIGATOR, rp.getRole());
         /*
          * Use the convenience method in order to avoid the effort of creating
@@ -103,7 +103,7 @@
     @Test
     public void testISO_URL() throws JAXBException {
         final String expected = getResponsiblePartyXML(Schemas.ISO_19139_ROOT);
-        final Responsibility rp = (Responsibility) XML.unmarshal(expected);
+        final ResponsibleParty rp = (ResponsibleParty) XML.unmarshal(expected);
         assertEquals(Role.PRINCIPAL_INVESTIGATOR, rp.getRole());
 
         final MarshallerPool pool = getMarshallerPool();
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java
index 69eaf7f..c0569ae 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.code;
 
 import java.util.Arrays;
-import java.util.EnumSet;
 import java.util.Collection;
 import javax.xml.bind.JAXBException;
 import org.opengis.metadata.identification.TopicCategory;
@@ -71,7 +70,6 @@
          * Unmarshall the above XML and verify that we find all the topic categories.
          */
         final Collection<TopicCategory> unmarshalled = unmarshal(DefaultDataIdentification.class, xml).getTopicCategories();
-        assertInstanceOf("topicCategory", EnumSet.class, unmarshalled);
         assertSetEquals(expected, unmarshalled);
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameterTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameterTest.java
index 2c54402..9865686 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameterTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameterTest.java
@@ -18,7 +18,6 @@
 
 import javax.xml.bind.JAXBException;
 import org.opengis.util.MemberName;
-import org.opengis.parameter.ParameterDirection;
 import org.apache.sis.util.iso.Names;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.test.XMLTestCase;
@@ -47,7 +46,6 @@
         param.memberName    = paramName;
         param.optionality   = true;
         param.repeatability = false;
-        param.direction     = ParameterDirection.IN;
         return param;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java
index 6b25518..a102aa3 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/sql/TestDatabase.java
@@ -66,7 +66,7 @@
         Path dir = DataDirectory.DATABASES.getDirectory();
         assumeNotNull("$SIS_DATA/Databases directory not found.", dir);
         dir = dir.resolve(name);
-        assumeTrue("Specified directory not found.", Files.isDirectory(dir));
+        assumeTrue(Files.isDirectory(dir));
         return dir;
     }
 
@@ -86,7 +86,7 @@
         try {
             ds = Initializer.forJavaDB("memory:" + name);
         } catch (ClassNotFoundException e) {
-            assumeNoException("No Derby or JavaDB driver has been found.", e);
+            assumeNoException(e);
             throw e;
         }
         ds.getClass().getMethod("setCreateDatabase", String.class).invoke(ds, "create");
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java
index 47de96f..0ebe4e9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataStandardTest.java
@@ -18,13 +18,11 @@
 
 import java.util.Set;
 import java.util.Map;
-import java.util.List;
 import java.util.HashSet;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.quality.Completeness;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.coverage.grid.RectifiedGrid;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
 import org.apache.sis.metadata.iso.acquisition.DefaultPlatform;
@@ -80,7 +78,6 @@
         assertFalse("isMetadata(IdentifiedObject)",       std.isMetadata(IdentifiedObject.class));
         assertFalse("isMetadata(SimpleIdentifiedObject)", std.isMetadata(SimpleIdentifiedObject.class));
         assertFalse("isMetadata(GeographicCRS)",          std.isMetadata(GeographicCRS.class));
-        assertFalse("isMetadata(RectifiedGrid)",          std.isMetadata(RectifiedGrid.class));
 
         std = MetadataStandard.ISO_19111;
         assertFalse("isMetadata(String)",                 std.isMetadata(String.class));
@@ -89,7 +86,6 @@
         assertTrue ("isMetadata(IdentifiedObject)",       std.isMetadata(IdentifiedObject.class));
         assertTrue ("isMetadata(SimpleIdentifiedObject)", std.isMetadata(SimpleIdentifiedObject.class));
         assertTrue ("isMetadata(GeographicCRS)",          std.isMetadata(GeographicCRS.class));
-        assertFalse("isMetadata(RectifiedGrid)",          std.isMetadata(RectifiedGrid.class));
 
         std = MetadataStandard.ISO_19123;
         assertFalse("isMetadata(String)",                 std.isMetadata(String.class));
@@ -98,7 +94,6 @@
         assertTrue ("isMetadata(IdentifiedObject)",       std.isMetadata(IdentifiedObject.class));       // Dependency
         assertTrue ("isMetadata(SimpleIdentifiedObject)", std.isMetadata(SimpleIdentifiedObject.class)); // Dependency
         assertTrue ("isMetadata(GeographicCRS)",          std.isMetadata(GeographicCRS.class));          // Dependency
-        assertTrue ("isMetadata(RectifiedGrid)",          std.isMetadata(RectifiedGrid.class));
     }
 
     /**
@@ -289,39 +284,6 @@
     }
 
     /**
-     * Tests the {@link MetadataStandard#ISO_19123} constant. Getters shall
-     * be accessible even if there is no implementation on the classpath.
-     */
-    @Test
-    @DependsOnMethod("testGetAccessor")
-    public void testWithoutImplementation() {
-        final MetadataStandard std = MetadataStandard.ISO_19123;
-        assertFalse("isMetadata(String)",          std.isMetadata(String.class));
-        assertTrue ("isMetadata(Citation)",        std.isMetadata(Citation.class));         // Transitive dependency
-        assertTrue ("isMetadata(DefaultCitation)", std.isMetadata(DefaultCitation.class));  // Transitive dependency
-        assertTrue ("isMetadata(RectifiedGrid)",   std.isMetadata(RectifiedGrid.class));
-        /*
-         * Ensure that the getters have been found.
-         */
-        final Map<String,String> names = std.asNameMap(RectifiedGrid.class, KeyNamePolicy.UML_IDENTIFIER, KeyNamePolicy.JAVABEANS_PROPERTY);
-        assertFalse("Getters should have been found even if there is no implementation.", names.isEmpty());
-        assertEquals("dimension", names.get("dimension"));
-        assertEquals("cells", names.get("cell"));
-        /*
-         * Ensure that the type are recognized, especially RectifiedGrid.getOffsetVectors()
-         * which is of type List<double[]>.
-         */
-        Map<String,Class<?>> types;
-        types = std.asTypeMap(RectifiedGrid.class, KeyNamePolicy.UML_IDENTIFIER, TypeValuePolicy.PROPERTY_TYPE);
-        assertEquals("The return type is the int primitive type.", Integer.TYPE, types.get("dimension"));
-        assertEquals("The offset vectors are stored in a List.",   List.class,   types.get("offsetVectors"));
-
-        types = std.asTypeMap(RectifiedGrid.class, KeyNamePolicy.UML_IDENTIFIER, TypeValuePolicy.ELEMENT_TYPE);
-        assertEquals("As elements in a list of dimensions.",       Integer.class,  types.get("dimension"));
-        assertEquals("As elements in the list of offset vectors.", double[].class, types.get("offsetVectors"));
-    }
-
-    /**
      * Tests serialization of pre-defined constants.
      */
     @Test
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
index cb2b58f..7c7cc6d 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
@@ -21,7 +21,7 @@
 import java.util.Random;
 import java.util.Collection;
 import org.opengis.util.CodeList;
-import org.opengis.util.ControlledVocabulary;
+import org.opengis.metadata.identification.CharacterSet;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.collection.CheckedContainer;
@@ -128,11 +128,16 @@
         if (Date.class.isAssignableFrom(type)) {
             return new Date(random.nextInt() * 1000L);
         }
-        if (ControlledVocabulary.class.isAssignableFrom(type)) try {
+        if (CodeList.class.isAssignableFrom(type)) try {
+            if (type == CharacterSet.class) {
+                // DefaultMetadata convert CharacterSet into Charset,
+                // but not all character sets are supported.
+                return CharacterSet.ISO_8859_1;
+            }
             if (type == CodeList.class) {
                 return null;
             }
-            final ControlledVocabulary[] codes = (ControlledVocabulary[]) type.getMethod("values", (Class[]) null).invoke(null, (Object[]) null);
+            final CodeList[] codes = (CodeList[]) type.getMethod("values", (Class[]) null).invoke(null, (Object[]) null);
             return codes[random.nextInt(codes.length)];
         } catch (Exception e) { // (ReflectiveOperationException) on JDK7 branch.
             fail(e.toString());
@@ -185,7 +190,7 @@
     public void testPropertyValues() {
         random = TestUtilities.createRandomNumberGenerator();
         for (final Class<?> type : types) {
-            if (!ControlledVocabulary.class.isAssignableFrom(type)) {
+            if (!CodeList.class.isAssignableFrom(type)) {
                 final Class<?> impl = getImplementation(type);
                 if (impl != null) {
                     assertTrue(type.isAssignableFrom(impl));
@@ -298,6 +303,14 @@
     @SuppressWarnings("deprecation")
     private static boolean skipTest(final Class<?> implementation, final String method) {
         return implementation == org.apache.sis.metadata.iso.maintenance.DefaultScopeDescription.class ||
+              (implementation == org.apache.sis.metadata.iso.DefaultMetadata.class &&
+               method.equals("getLocales")) || // Fail when 'locale' value equals 'language'.
+              (implementation == org.apache.sis.metadata.iso.DefaultMetadata.class &&
+               method.equals("getDataSetUri")) ||
+              (implementation == org.apache.sis.metadata.iso.citation.DefaultContact.class &&
+               method.equals("getPhone")) || // Deprecated method replaced by 'getPhones()'.
+              (implementation == org.apache.sis.metadata.iso.lineage.DefaultSource.class &&
+               method.equals("getScaleDenominator")) || // Deprecated method replaced by 'getSourceSpatialResolution()'.
               (implementation == org.apache.sis.metadata.iso.citation.DefaultResponsibleParty.class &&
                method.equals("getParties"));
     }
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 bc7994d..94ff5a4 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
@@ -23,7 +23,6 @@
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Date;
-import java.nio.charset.Charset;
 
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
@@ -32,10 +31,9 @@
 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;
 import org.opengis.metadata.content.CoverageContentType;
 import org.opengis.metadata.content.CoverageDescription;
 import org.opengis.metadata.identification.*; // Really using almost everything.
@@ -43,19 +41,22 @@
 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;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.util.InternationalString;
 import org.opengis.util.GenericName;
-import org.opengis.temporal.Duration;
 
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
+import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
 import org.apache.sis.metadata.iso.content.DefaultCoverageDescription;
+import org.apache.sis.metadata.iso.identification.AbstractIdentification;
+import org.apache.sis.metadata.iso.identification.DefaultAssociatedResource;
 import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -176,15 +177,15 @@
             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,
-            Citation.class, "getGraphics",                "graphics",                "graphic",               "Graphics",                   BrowseGraphic[].class,
-            Citation.class, "getOnlineResources",         "onlineResources",         "onlineResource",        "Online resources",           OnlineResource[].class);
+     DefaultCitation.class, "getGraphics",                "graphics",                "graphic",               "Graphics",                   BrowseGraphic[].class,
+     DefaultCitation.class, "getOnlineResources",         "onlineResources",         "onlineResource",        "Online resources",           OnlineResource[].class);
     }
 
     /**
@@ -204,27 +205,26 @@
             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, "getResourceMaintenances",       "resourceMaintenances",       "resourceMaintenance",       "Resource maintenances",        MaintenanceInformation[].class,
             Identification.class, "getGraphicOverviews",           "graphicOverviews",           "graphicOverview",           "Graphic overviews",            BrowseGraphic[].class,
             Identification.class, "getResourceFormats",            "resourceFormats",            "resourceFormat",            "Resource formats",             Format[].class,
             Identification.class, "getDescriptiveKeywords",        "descriptiveKeywords",        "descriptiveKeywords",       "Descriptive keywords",         Keywords[].class,
             Identification.class, "getResourceSpecificUsages",     "resourceSpecificUsages",     "resourceSpecificUsage",     "Resource specific usages",     Usage[].class,
             Identification.class, "getResourceConstraints",        "resourceConstraints",        "resourceConstraints",       "Resource constraints",         Constraints[].class,
-            Identification.class, "getSpatialRepresentationTypes", "spatialRepresentationTypes", "spatialRepresentationType", "Spatial representation types", SpatialRepresentationType[].class,
-            Identification.class, "getSpatialResolutions",         "spatialResolutions",         "spatialResolution",         "Spatial resolutions",          Resolution[].class,
+        DataIdentification.class, "getSpatialRepresentationTypes", "spatialRepresentationTypes", "spatialRepresentationType", "Spatial representation types", SpatialRepresentationType[].class,
+        DataIdentification.class, "getSpatialResolutions",         "spatialResolutions",         "spatialResolution",         "Spatial resolutions",          Resolution[].class,
         DataIdentification.class, "getLanguages",                  "languages",                  "language",                  "Languages",                    Locale[].class,
-        DataIdentification.class, "getCharacterSets",              "characterSets",              "characterSet",              "Character sets",               Charset[].class,
-            Identification.class, "getTopicCategories",            "topicCategories",            "topicCategory",             "Topic categories",             TopicCategory[].class,
+        DataIdentification.class, "getCharacterSets",              "characterSets",              "characterSet",              "Character sets",               CharacterSet[].class,
+        DataIdentification.class, "getTopicCategories",            "topicCategories",            "topicCategory",             "Topic categories",             TopicCategory[].class,
         DataIdentification.class, "getEnvironmentDescription",     "environmentDescription",     "environmentDescription",    "Environment description",      InternationalString.class,
-            Identification.class, "getExtents",                    "extents",                    "extent",                    "Extents",                      Extent[].class,
+        DataIdentification.class, "getExtents",                    "extents",                    "extent",                    "Extents",                      Extent[].class,
         DataIdentification.class, "getSupplementalInformation",    "supplementalInformation",    "supplementalInformation",   "Supplemental information",     InternationalString.class,
-            Identification.class, "getAdditionalDocumentations",   "additionalDocumentations",   "additionalDocumentation",   "Additional documentations",    Citation[].class,
-            Identification.class, "getAssociatedResources",        "associatedResources",        "associatedResource",        "Associated resources",         AssociatedResource[].class,
-            Identification.class, "getProcessingLevel",            "processingLevel",            "processingLevel",           "Processing level",             Identifier.class,
-            Identification.class, "getTemporalResolutions",        "temporalResolutions",        "temporalResolution",        "Temporal resolutions",         Duration[].class);
+    AbstractIdentification.class, "getAdditionalDocumentations",   "additionalDocumentations",   "additionalDocumentation",   "Additional documentations",    Citation[].class,
+    AbstractIdentification.class, "getAssociatedResources",        "associatedResources",        "associatedResource",        "Associated resources",         DefaultAssociatedResource[].class,
+    AbstractIdentification.class, "getProcessingLevel",            "processingLevel",            "processingLevel",           "Processing level",             Identifier.class);
     }
 
     /**
@@ -242,10 +242,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);
     }
@@ -383,7 +383,7 @@
         /*
          * Compares with the non-deprecated property.
          */
-        final Collection<AttributeGroup> groups = instance.getAttributeGroups();
+        final Collection<DefaultAttributeGroup> groups = instance.getAttributeGroups();
         assertSame(groups, accessor.get(indexOfReplacement, instance));
         assertEquals(CoverageContentType.IMAGE, getSingleton(getSingleton(groups).getContentTypes()));
         /*
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 a983638..358baa4 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/SpecialCasesTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
index 4f3ec8e..1d208be 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/SpecialCasesTest.java
@@ -37,7 +37,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.4
  * @module
  */
 @DependsOn(PropertyAccessorTest.class)
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 2d6b1a1..7ab6b63 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
@@ -32,7 +32,6 @@
 import org.junit.Test;
 
 import static org.junit.Assert.*;
-import static java.util.Collections.singleton;
 import static org.apache.sis.test.TestUtilities.createRandomNumberGenerator;
 
 
@@ -66,7 +65,7 @@
     static DefaultCitation metadataWithoutCollections() {
         final DefaultCitation citation = new DefaultCitation("Some title");
         citation.setEdition(new SimpleInternationalString("Some edition"));
-        citation.setOtherCitationDetails(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 b406cbe..ad65a2d 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
@@ -20,15 +20,14 @@
 import org.opengis.metadata.citation.Address;
 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;
@@ -83,7 +82,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.
@@ -92,7 +92,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,16 +178,16 @@
               "Alternate title (2 of 2)",
               "Edition",
               "Cited responsible party (1 of 2)",
+                "Role",
                 "Party",
                   "Name",
-                "Role",
               "Cited responsible party (2 of 2)",
+                "Role",
                 "Party",
                   "Name",
                   "Contact info",
                     "Address",
                       "Electronic mail address",
-                "Role",
               "Presentation form (1 of 2)",
               "Presentation form (2 of 2)",
               "Other citation details");
@@ -209,16 +210,16 @@
               "alternateTitle",
               "edition",
               "citedResponsibleParty",
+                "role",
                 "party",
                   "name",
-                "role",
               "citedResponsibleParty",
+                "role",
                 "party",
                   "name",
                   "contactInfo",
                     "address",
                       "electronicMailAddress",
-                "role",
               "presentationForm",
               "presentationForm",
               "otherCitationDetails");
@@ -240,19 +241,19 @@
               ONE,          // alternateTitle
               null,         // edition
               ZERO,         // citedResponsibleParty
+                null,       // role
                 ZERO,       // party (organisation)
                   null,     // name
-                null,       // role
               ONE,          // citedResponsibleParty
+                null,       // role
                 ZERO,       // party (individual)
                   null,     // name
                   ZERO,     // contactInfo
                     ZERO,   // address
                       ZERO, // electronicMailAddress
-                null,       // role
               ZERO,         // presentationForm
               ONE,          // presentationForm
-              ZERO);        // otherCitationDetails
+              null);        // otherCitationDetails
     }
 
     /**
@@ -268,17 +269,17 @@
               InternationalString.class,
               InternationalString.class,
               InternationalString.class,
-              Responsibility.class,
-                Party.class,
-                  InternationalString.class,
+              ResponsibleParty.class,
                 Role.class,
-              Responsibility.class,
-                Party.class,
+                AbstractParty.class,
+                  InternationalString.class,
+              ResponsibleParty.class,
+                Role.class,
+                AbstractParty.class,
                   InternationalString.class,
                   Contact.class,
                     Address.class,
                       String.class,
-                Role.class,
               PresentationForm.class,
               PresentationForm.class,
               InternationalString.class);
@@ -298,16 +299,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");
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 f9f5edc..0cc6dd4 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
@@ -27,7 +27,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,18 +87,17 @@
             "  ├─Alternate title………………………………………………… Andākarento\n" +
             "  ├─Identifier\n" +
             "  │   ├─Code…………………………………………………………………… 9782505004509\n" +
-            "  │   ├─Authority\n" +
-            "  │   │   ├─Title……………………………………………………… International Standard Book Number\n" +
-            "  │   │   └─Alternate title…………………………… ISBN\n" +
-            "  │   └─Code space…………………………………………………… ISBN\n"+
+            "  │   └─Authority\n" +
+            "  │       ├─Title……………………………………………………… International Standard Book Number\n" +
+            "  │       └─Alternate title…………………………… ISBN\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   └─Name………………………………………………………… Testsuya Toyoda\n" +
-            "  │   └─Role…………………………………………………………………… Author\n" +
+            "  │   ├─Role…………………………………………………………………… Author\n" +
+            "  │   └─Party\n" +
+            "  │       └─Name………………………………………………………… Testsuya Toyoda\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
+            "  │   ├─Role…………………………………………………………………… EDITOR\n" +
             "  │   ├─Party\n" +
             "  │   │   └─Name………………………………………………………… Kōdansha\n" +
-            "  │   ├─Role…………………………………………………………………… Editor\n" +
             "  │   └─Extent\n" +
             "  │       ├─Description……………………………………… World\n" +
             "  │       └─Geographic element\n" +
@@ -122,7 +121,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());
@@ -186,7 +185,7 @@
             "  ├─Alternate title (2 of 3)………… Orange\n" +
             "  ├─Alternate title (3 of 3)………… Kiwi\n" +
             "  ├─Presentation form (1 of 3)…… Image digital\n" +
-            "  ├─Presentation form (2 of 3)…… Audio digital\n" +
+            "  ├─Presentation form (2 of 3)…… AUDIO-DIGITAL\n" + // Missing localization resource for that one.
             "  └─Presentation form (3 of 3)…… Test\n",
             text);
     }
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 8c20cea..3f0e4d4 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
@@ -59,16 +59,16 @@
             "  ├─Alternate title (2 of 2)…………………………………………… Second alternate title\n" +
             "  ├─Edition………………………………………………………………………………………… Some edition\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   └─Name…………………………………………………………………………… Some organisation\n" +
-            "  │   └─Role……………………………………………………………………………………… Distributor\n" +
+            "  │   ├─Role……………………………………………………………………………………… Distributor\n" +
+            "  │   └─Party\n" +
+            "  │       └─Name…………………………………………………………………………… Some organisation\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   ├─Name…………………………………………………………………………… Some person of contact\n" +
-            "  │   │   └─Contact info\n" +
-            "  │   │       └─Address\n" +
-            "  │   │           └─Electronic mail address…… Some email\n" +
-            "  │   └─Role……………………………………………………………………………………… Point of contact\n" +
+            "  │   ├─Role……………………………………………………………………………………… Point of contact\n" +
+            "  │   └─Party\n" +
+            "  │       ├─Name…………………………………………………………………………… Some person of contact\n" +
+            "  │       └─Contact info\n" +
+            "  │           └─Address\n" +
+            "  │               └─Electronic mail address…… Some email\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 db1d971..3ee540e 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<String,Class<?>>("edition",               InternationalString.class),
             new SimpleEntry<String,Class<?>>("editionDate",           Date.class),
             new SimpleEntry<String,Class<?>>("identifier",            Identifier.class),
-            new SimpleEntry<String,Class<?>>("citedResponsibleParty", Responsibility.class),
+            new SimpleEntry<String,Class<?>>("citedResponsibleParty", ResponsibleParty.class),
             new SimpleEntry<String,Class<?>>("presentationForm",      PresentationForm.class),
             new SimpleEntry<String,Class<?>>("series",                Series.class),
             new SimpleEntry<String,Class<?>>("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 22131d2..ccdddd1 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.iso.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;
@@ -67,7 +67,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.
@@ -90,7 +90,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));
@@ -171,7 +171,6 @@
             new SimpleEntry<String,Object>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<String,Object>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<String,Object>("presentationForms",       emptySet()),
-            new SimpleEntry<String,Object>("otherCitationDetails",    emptyList()),
             new SimpleEntry<String,Object>("ISBN",                    "9782505004509"),
             new SimpleEntry<String,Object>("graphics",                emptyList()),
             new SimpleEntry<String,Object>("onlineResources",         emptyList())
@@ -202,7 +201,6 @@
             new SimpleEntry<String,Object>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<String,Object>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<String,Object>("presentationForms",       emptySet()),
-            new SimpleEntry<String,Object>("otherCitationDetails",    emptyList()),
             new SimpleEntry<String,Object>("ISBN",                    "9782505004509"),
             new SimpleEntry<String,Object>("graphics",                emptyList()),
             new SimpleEntry<String,Object>("onlineResources",         emptyList())
@@ -233,7 +231,7 @@
             new SimpleEntry<String,Object>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<String,Object>("presentationForms",       emptySet()),
             new SimpleEntry<String,Object>("series",                  null),
-            new SimpleEntry<String,Object>("otherCitationDetails",    emptyList()),
+            new SimpleEntry<String,Object>("otherCitationDetails",    null),
 //          new SimpleEntry<String,Object>("collectiveTitle",         null),  -- deprecated as of ISO 19115:2014.
             new SimpleEntry<String,Object>("ISBN",                    "9782505004509"),
             new SimpleEntry<String,Object>("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 60b1910..a19c1f6 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
@@ -18,7 +18,7 @@
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import org.opengis.util.ControlledVocabulary;
+import org.opengis.util.CodeList;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
 import org.apache.sis.internal.jaxb.Context;
@@ -53,10 +53,8 @@
     /**
      * Creates a new test case with all GeoAPI interfaces and code lists to test.
      */
-    @SuppressWarnings("deprecation")
     public AllMetadataTest() {
         super(MetadataStandard.ISO_19115,
-            org.opengis.annotation.Obligation.class,
             org.opengis.metadata.ApplicationSchemaInformation.class,
             org.opengis.metadata.Datatype.class,
             org.opengis.metadata.ExtendedElementInformation.class,
@@ -64,7 +62,6 @@
             org.opengis.metadata.Identifier.class,
             org.opengis.metadata.Metadata.class,
             org.opengis.metadata.MetadataExtensionInformation.class,
-            org.opengis.metadata.MetadataScope.class,
             org.opengis.metadata.PortrayalCatalogueReference.class,
             org.opengis.metadata.acquisition.AcquisitionInformation.class,
             org.opengis.metadata.acquisition.Context.class,
@@ -91,9 +88,7 @@
             org.opengis.metadata.citation.DateType.class,
             org.opengis.metadata.citation.OnLineFunction.class,
             org.opengis.metadata.citation.OnlineResource.class,
-            org.opengis.metadata.citation.Party.class,
             org.opengis.metadata.citation.PresentationForm.class,
-            org.opengis.metadata.citation.Responsibility.class,
             org.opengis.metadata.citation.ResponsibleParty.class,
             org.opengis.metadata.citation.Role.class,
             org.opengis.metadata.citation.Series.class,
@@ -103,7 +98,6 @@
             org.opengis.metadata.constraint.LegalConstraints.class,
             org.opengis.metadata.constraint.Restriction.class,
             org.opengis.metadata.constraint.SecurityConstraints.class,
-            org.opengis.metadata.content.AttributeGroup.class,
             org.opengis.metadata.content.Band.class,
             org.opengis.metadata.content.BandDefinition.class,
             org.opengis.metadata.content.ContentInformation.class,
@@ -115,7 +109,6 @@
             org.opengis.metadata.content.PolarizationOrientation.class,
             org.opengis.metadata.content.RangeDimension.class,
             org.opengis.metadata.content.RangeElementDescription.class,
-            org.opengis.metadata.content.SampleDimension.class,
             org.opengis.metadata.content.TransferFunctionType.class,
             org.opengis.metadata.distribution.DataFile.class,
             org.opengis.metadata.distribution.DigitalTransferOptions.class,
@@ -135,20 +128,15 @@
             org.opengis.metadata.extent.TemporalExtent.class,
             org.opengis.metadata.extent.VerticalExtent.class,
             org.opengis.metadata.identification.AggregateInformation.class,
-            org.opengis.metadata.identification.AssociatedResource.class,
             org.opengis.metadata.identification.AssociationType.class,
             org.opengis.metadata.identification.BrowseGraphic.class,
             org.opengis.metadata.identification.CharacterSet.class,
-            org.opengis.metadata.identification.CoupledResource.class,
             org.opengis.metadata.identification.DataIdentification.class,
             org.opengis.metadata.identification.Identification.class,
             org.opengis.metadata.identification.InitiativeType.class,
             org.opengis.metadata.identification.Keywords.class,
-            org.opengis.metadata.identification.KeywordClass.class,
             org.opengis.metadata.identification.KeywordType.class,
             org.opengis.metadata.identification.Progress.class,
-            org.opengis.metadata.identification.OperationChainMetadata.class,
-            org.opengis.metadata.identification.OperationMetadata.class,
             org.opengis.metadata.identification.RepresentativeFraction.class,
             org.opengis.metadata.identification.Resolution.class,
             org.opengis.metadata.identification.ServiceIdentification.class,
@@ -163,7 +151,6 @@
             org.opengis.metadata.lineage.Source.class,
             org.opengis.metadata.maintenance.MaintenanceFrequency.class,
             org.opengis.metadata.maintenance.MaintenanceInformation.class,
-            org.opengis.metadata.maintenance.Scope.class,
             org.opengis.metadata.maintenance.ScopeCode.class,
             org.opengis.metadata.maintenance.ScopeDescription.class,
             org.opengis.metadata.quality.AbsoluteExternalPositionalAccuracy.class,
@@ -187,6 +174,7 @@
             org.opengis.metadata.quality.QuantitativeResult.class,
             org.opengis.metadata.quality.RelativeInternalPositionalAccuracy.class,
             org.opengis.metadata.quality.Result.class,
+            org.opengis.metadata.quality.Scope.class,
             org.opengis.metadata.quality.TemporalAccuracy.class,
             org.opengis.metadata.quality.TemporalConsistency.class,
             org.opengis.metadata.quality.TemporalValidity.class,
@@ -320,9 +308,12 @@
              */
             return null;
         }
+        String identifier = type.getAnnotation(UML.class).identifier();
+        if (identifier.equals("DQ_Scope")) {  // Old name in ISO 19115:2003
+            identifier = "MD_Scope";          // New name in ISO 19115:2014
+        }
         final String classname = "org.apache.sis.internal.jaxb." +
-              (ControlledVocabulary.class.isAssignableFrom(type) ? "code" : "metadata") +
-              '.' + type.getAnnotation(UML.class).identifier();
+              (CodeList.class.isAssignableFrom(type) ? "code" : "metadata") + '.' + identifier;
         final Class<?> wrapper = Class.forName(classname);
         assertTrue("Expected a final class for " + wrapper.getName(), Modifier.isFinal(wrapper.getModifiers()));
         return wrapper;
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
index a425b62..d6f8284 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
@@ -23,20 +23,17 @@
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationHandler;
-import java.nio.charset.Charset;
 import javax.xml.bind.JAXBException;
 import org.opengis.util.NameFactory;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.identification.*;
 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;
 import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.util.InternationalString;
-import org.opengis.temporal.Duration;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -120,17 +117,15 @@
             @Override public InternationalString                   getSupplementalInformation()    {return null;}
             @Override public Citation                              getCitation()                   {return null;}
             @Override public InternationalString                   getPurpose()                    {return null;}
-            @Override public Identifier                            getProcessingLevel()            {return null;}
             @Override public Collection<SpatialRepresentationType> getSpatialRepresentationTypes() {return null;}
             @Override public Collection<Resolution>                getSpatialResolutions()         {return null;}
-            @Override public Collection<Duration>                  getTemporalResolutions()        {return null;}
             @Override public Collection<Locale>                    getLanguages()                  {return null;}
-            @Override public Collection<Charset>                   getCharacterSets()              {return null;}
+            @Override public Collection<CharacterSet>              getCharacterSets()              {return null;}
             @Override public Collection<TopicCategory>             getTopicCategories()            {return null;}
             @Override public Collection<Extent>                    getExtents()                    {return null;}
-            @Override public Collection<InternationalString>       getCredits()                    {return null;}
+            @Override public Collection<String>                    getCredits()                    {return null;}
             @Override public Collection<Progress>                  getStatus()                     {return null;}
-            @Override public Collection<Responsibility>            getPointOfContacts()            {return null;}
+            @Override public Collection<ResponsibleParty>          getPointOfContacts()            {return null;}
             @Override public Collection<MaintenanceInformation>    getResourceMaintenances()       {return null;}
             @Override public Collection<BrowseGraphic>             getGraphicOverviews()           {return null;}
             @Override public Collection<Format>                    getResourceFormats()            {return null;}
@@ -138,8 +133,6 @@
             @Override public Collection<Usage>                     getResourceSpecificUsages()     {return null;}
             @Override public Collection<Constraints>               getResourceConstraints()        {return null;}
 @Deprecated @Override public Collection<AggregateInformation>      getAggregationInfo()            {return null;}
-            @Override public Collection<AssociatedResource>        getAssociatedResources()        {return null;}
-            @Override public Collection<Citation>                  getAdditionalDocumentations()   {return null;}
         };
         final DefaultMetadata data = new DefaultMetadata();
         data.setIdentificationInfo(singleton(identification));
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java
index 55a5947..4a23ce5 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/DefaultMetadataTest.java
@@ -25,7 +25,6 @@
 import java.net.URISyntaxException;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.JAXBException;
-import org.opengis.metadata.MetadataScope;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.maintenance.ScopeCode;
@@ -130,7 +129,7 @@
          * Verify warning message emitted during unmarshalling.
          */
         assertEquals("warning", "NullCollectionElement_1", resourceKey);
-        assertArrayEquals("warning", new String[] {"CheckedArrayList<Responsibility>"}, parameters);
+        assertArrayEquals("warning", new String[] {"CheckedArrayList<ResponsibleParty>"}, parameters);
     }
 
     /**
@@ -241,9 +240,9 @@
         /*
          * The above deprecated methods shall have created MetadataScope object. Verify that.
          */
-        final Collection<MetadataScope> scopes = metadata.getMetadataScopes();
-        final Iterator<MetadataScope> it = scopes.iterator();
-        MetadataScope scope = it.next();
+        final Collection<DefaultMetadataScope> scopes = metadata.getMetadataScopes();
+        final Iterator<DefaultMetadataScope> it = scopes.iterator();
+        DefaultMetadataScope scope = it.next();
         assertEquals("metadataScopes[0].name", "Bridges", scope.getName().toString());
         assertEquals("metadataScopes[0].resourceScope", ScopeCode.FEATURE_TYPE, scope.getResourceScope());
         scope = it.next();
@@ -287,7 +286,7 @@
          */
         Date creation = date("2014-10-07 00:00:00");
         final DefaultCitationDate[] dates = new DefaultCitationDate[] {
-                new DefaultCitationDate(date("2014-10-09 00:00:00"), DateType.LAST_UPDATE),
+                new DefaultCitationDate(date("2014-10-09 00:00:00"), DateType.valueOf("LAST_UPDATE")),
                 new DefaultCitationDate(creation, DateType.CREATION)
         };
         metadata.setDateInfo(Arrays.asList(dates));
@@ -336,7 +335,5 @@
         final DefaultMetadata metadata = new DefaultMetadata();
         metadata.setDataSetUri("file:/tmp/myfile.txt");
         assertEquals("file:/tmp/myfile.txt", metadata.getDataSetUri());
-        assertEquals("file:/tmp/myfile.txt", getSingleton(getSingleton(metadata.getIdentificationInfo())
-                .getCitation().getOnlineResources()).getLinkage().toString());
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
index 9892ccf..4444b6a 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
@@ -33,7 +33,7 @@
 import org.junit.Test;
 
 import static org.apache.sis.test.MetadataAssert.*;
-import static org.opengis.metadata.Identifier.*;
+import static org.opengis.referencing.ReferenceIdentifier.*;
 
 
 /**
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
index 42097b9..222698f 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
@@ -21,6 +21,7 @@
 import java.lang.reflect.Field;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.CitationConstant;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.test.DependsOnMethod;
@@ -101,9 +102,9 @@
         assertEquals("ISO:19115-2", getIdentifier(ISO_19115.get(1)));  // and could be changed in future SIS versions.
         assertEquals("OGC:WMS",     getIdentifier(WMS));
         assertIdentifierEquals("OGC:06-042", null, "OGC", null, "06-042",
-                ((List<? extends Identifier>) WMS.getIdentifiers()).get(1));
+                (ReferenceIdentifier) ((List<? extends Identifier>) WMS.getIdentifiers()).get(1));
         assertIdentifierEquals("ISO:19128", null, "ISO", "2005", "19128",
-                ((List<? extends Identifier>) WMS.getIdentifiers()).get(2));
+                (ReferenceIdentifier) ((List<? extends Identifier>) WMS.getIdentifiers()).get(2));
     }
 
     /**
@@ -190,7 +191,7 @@
      * Returns the responsible party for the given constant.
      */
     private static String getCitedResponsibleParty(final Citation citation) {
-        return getSingleton(getSingleton(citation.getCitedResponsibleParties()).getParties()).getName().toString(Locale.US);
+        return getSingleton(citation.getCitedResponsibleParties()).getOrganisationName().toString(Locale.US);
     }
 
     /**
@@ -204,7 +205,7 @@
     public void testEPSG() {
         final Identifier identifier = getSingleton(EPSG.getIdentifiers());
         assertEquals("EPSG", getUnicodeIdentifier(EPSG));
-        assertEquals("IOGP", identifier.getCodeSpace());
+        assertEquals("IOGP", ((ReferenceIdentifier) identifier).getCodeSpace());
         assertEquals("EPSG", identifier.getCode());
     }
 
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 9b65665..af4d3c9 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
@@ -26,9 +26,8 @@
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.DateType;
-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.PresentationForm;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.xml.IdentifierMap;
@@ -78,9 +77,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.valueOf("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;
     }
 
@@ -151,12 +156,12 @@
         /*
          * Verify the author metadata.
          */
-        final Responsibility re = CollectionsExt.first(original.getCitedResponsibleParties());
-        final Responsibility ra = CollectionsExt.first(clone   .getCitedResponsibleParties());
+        final ResponsibleParty re = CollectionsExt.first(original.getCitedResponsibleParties());
+        final ResponsibleParty ra = CollectionsExt.first(clone   .getCitedResponsibleParties());
         assertNotSame("citedResponsibleParty", re, ra);
         assertSame("role", re.getRole(), ra.getRole());
-        assertSame("name", getSingleton(re.getParties()).getName(),
-                           getSingleton(ra.getParties()).getName());
+        assertSame("name", re.getIndividualName(),
+                           ra.getIndividualName());
     }
 
     /**
@@ -187,11 +192,12 @@
         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))
-        ));
-        c.getDates().add(new DefaultCitationDate(TestUtilities.date("2015-10-17 00:00:00"), DateType.ADOPTED));
+        final DefaultResponsibleParty r1 = new DefaultResponsibleParty(Role.ORIGINATOR);
+        final DefaultResponsibleParty r2 = new DefaultResponsibleParty(Role.valueOf("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.valueOf("adopted")));
         assertMarshalEqualsFile(XML_FILE, c, "xlmns:*", "xsi:schemaLocation");
     }
 
@@ -210,23 +216,23 @@
 
         final CitationDate date = getSingleton(c.getDates());
         assertEquals("date", date.getDate(), TestUtilities.date("2015-10-17 00:00:00"));
-        assertEquals("dateType", date.getDateType(), DateType.ADOPTED);
+        assertEquals("dateType", date.getDateType(), DateType.valueOf("adopted"));
 
-        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.", contact.getContactInstructions().toString());
 
         // Thanks to xlink:href, the Contact shall be the same instance than above.
-        assertSame("contact", contact, assertResponsibilityEquals(Role.FUNDER, "Robin Hood", it.next()));
+        assertSame("contact", contact, assertResponsibilityEquals(Role.valueOf("funder"), "Robin Hood", it.next()));
         assertFalse(it.hasNext());
     }
 
     /**
      * Asserts that the given responsibility has the expected properties, then returns its contact info.
      */
-    private static Contact assertResponsibilityEquals(final Role role, final String name, final Responsibility actual) {
+    private static Contact assertResponsibilityEquals(final Role role, final String name, final ResponsibleParty actual) {
         assertEquals("role", role, actual.getRole());
-        final Party p = getSingleton(actual.getParties());
+        final AbstractParty p = getSingleton(((DefaultResponsibleParty) actual).getParties());
         assertEquals("name", name, p.getName().toString());
         return getSingleton(p.getContactInfo());
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java
index 0a38016..8dc0810 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultContactTest.java
@@ -20,8 +20,8 @@
 import java.util.Collection;
 import java.util.logging.LogRecord;
 import org.opengis.metadata.citation.Telephone;
-import org.opengis.metadata.citation.TelephoneType;
 import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
 import org.apache.sis.util.logging.WarningListener;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.XMLTestCase;
@@ -92,10 +92,10 @@
     @SuppressWarnings("deprecation")
     public void testSetPhones() {
         init();
-        final DefaultTelephone   tel1 = new DefaultTelephone("00.01", TelephoneType.SMS);
-        final DefaultTelephone   tel2 = new DefaultTelephone("00.02", TelephoneType.VOICE);
-        final DefaultTelephone   tel3 = new DefaultTelephone("00.03", TelephoneType.FACSIMILE);
-        final DefaultTelephone   tel4 = new DefaultTelephone("00.04", TelephoneType.VOICE);
+        final DefaultTelephone   tel1 = new DefaultTelephone("00.01", UnsupportedCodeList.valueOf("SMS"));
+        final DefaultTelephone   tel2 = new DefaultTelephone("00.02", UnsupportedCodeList.VOICE);
+        final DefaultTelephone   tel3 = new DefaultTelephone("00.03", UnsupportedCodeList.FACSIMILE);
+        final DefaultTelephone   tel4 = new DefaultTelephone("00.04", UnsupportedCodeList.VOICE);
         final DefaultTelephone[] tels = new DefaultTelephone[] {tel1, tel2, tel3, tel4};
         final DefaultContact  contact = new DefaultContact();
         contact.setPhones(Arrays.asList(tel1, tel2, tel3, tel4));
@@ -106,7 +106,7 @@
          */
         assertSame("getPhone", tel2, contact.getPhone()); // Shall ignore the TelephoneType.SMS.
         assertEquals("warningOccured", "IgnoredPropertyAssociatedTo_1", resourceKey);
-        assertArrayEquals("warningOccured", new String[] {"TelephoneType[SMS]"}, parameters);
+        assertArrayEquals("warningOccured", new String[] {"SMS"}, parameters);
         verifyLegacyLists(tels);
     }
 
@@ -164,8 +164,6 @@
         final Telephone view;
         if (hideSIS) {
             view = new Telephone() {
-                @Override public String             getNumber()     {return tel.getNumber();}
-                @Override public TelephoneType      getNumberType() {return tel.getNumberType();}
                 @Override public Collection<String> getVoices()     {return tel.getVoices();}
                 @Override public Collection<String> getFacsimiles() {return tel.getFacsimiles();}
             };
@@ -180,9 +178,9 @@
         contact.setPhone(view);
         verifyLegacyLists(view);
         assertArrayEquals("getPhones", new DefaultTelephone[] {
-                new DefaultTelephone("00.02", TelephoneType.VOICE),
-                new DefaultTelephone("00.04", TelephoneType.VOICE),
-                new DefaultTelephone("00.03", TelephoneType.FACSIMILE)
+                new DefaultTelephone("00.02", UnsupportedCodeList.VOICE),
+                new DefaultTelephone("00.04", UnsupportedCodeList.VOICE),
+                new DefaultTelephone("00.03", UnsupportedCodeList.FACSIMILE)
             }, contact.getPhones().toArray());
     }
 }
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 dac1188..f59d13b 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
@@ -43,8 +43,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);
         assertXmlEquals("<gmd:CI_Citation xmlns:gco=\"" + Namespaces.GCO + '"' +
@@ -55,7 +56,7 @@
                 "        <gco:CharacterString>An author</gco:CharacterString>\n" +
                 "      </gmd:individualName>\n" +
                 "      <gmd:role>\n" +
-                "        <gmd:CI_RoleCode codeList=\"http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#CI_RoleCode\" codeListValue=\"author\" codeSpace=\"eng\">Author</gmd:CI_RoleCode>\n" +
+                "        <gmd:CI_RoleCode codeList=\"http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#CI_RoleCode\" codeListValue=\"author\">Author</gmd:CI_RoleCode>\n" +
                 "      </gmd:role>\n" +
                 "    </gmd:CI_ResponsibleParty>\n" +
                 "  </gmd:citedResponsibleParty>\n" +
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 8bfeaf2..b758f61 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.Constants;
 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("http://www.epsg.org"));
         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/constraint/DefaultLegalConstraintsTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java
index 2215978..d7e370c 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/constraint/DefaultLegalConstraintsTest.java
@@ -122,7 +122,7 @@
     }
 
     /**
-     * Tests (un)marshalling of a XML fragment containing the {@link Restriction#LICENCE} code.
+     * Tests (un)marshalling of a XML fragment containing the {@link Restriction#LICENSE} code.
      * The spelling changed between ISO 19115:2003 and 19115:2014, from "license" to "licence".
      * We need to ensure that XML marshalling use the old spelling, until the XML schema is updated.
      *
@@ -135,19 +135,18 @@
                 "  <gmd:useConstraints>\n" +
                 "    <gmd:MD_RestrictionCode"
                         + " codeList=\"http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#MD_RestrictionCode\""
-                        + " codeListValue=\"license\""                              // Note the "s" - from old ISO 19115:2013 spelling.
-                        + " codeSpace=\"eng\">Licence</gmd:MD_RestrictionCode>\n" + // Note the "c" - this one come from resource file.
+                        + " codeListValue=\"license\">License</gmd:MD_RestrictionCode>\n" +
                 "  </gmd:useConstraints>\n" +
                 "</gmd:MD_LegalConstraints>\n";
 
         final DefaultLegalConstraints c = new DefaultLegalConstraints();
-        c.setUseConstraints(singleton(Restriction.LICENCE));
+        c.setUseConstraints(singleton(Restriction.LICENSE));
         assertXmlEquals(xml, marshal(c), "xmlns:*");
         /*
          * Unmarshall and ensure that we got back the original LICENCE code, not a new "LICENSE" code.
          */
         final DefaultLegalConstraints actual = unmarshal(xml);
-        assertSame(Restriction.LICENCE, getSingleton(actual.getUseConstraints()));
+        assertSame(Restriction.LICENSE, getSingleton(actual.getUseConstraints()));
         assertEquals(c, actual);
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResourceTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResourceTest.java
index d773347..f12982d 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResourceTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResourceTest.java
@@ -20,9 +20,7 @@
 import org.opengis.util.NameFactory;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.identification.CoupledResource;
-import org.opengis.metadata.identification.OperationMetadata;
-import org.opengis.metadata.identification.DistributedComputingPlatform;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
 import org.apache.sis.internal.jaxb.metadata.replace.ServiceParameterTest;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.xml.NilReason;
@@ -48,8 +46,9 @@
      * Creates the resource to use for testing purpose.
      */
     static DefaultCoupledResource create() {
-        final DefaultOperationMetadata operation = new DefaultOperationMetadata("Get Map",
-                DistributedComputingPlatform.WEB_SERVICES, null);
+        final DefaultOperationMetadata operation = new DefaultOperationMetadata();
+        operation.setOperationName("Get Map");
+        operation.setDistributedComputingPlatforms(singleton(UnsupportedCodeList.valueOf("WEB_SERVICES")));
         operation.setParameters(singleton((ParameterDescriptor<?>) ServiceParameterTest.create()));
         operation.setConnectPoints(singleton(NilReason.MISSING.createNilObject(OnlineResource.class)));
 
@@ -66,13 +65,13 @@
     @Test
     public void testOperationNameResolve() {
         final DefaultCoupledResource resource  = DefaultCoupledResourceTest.create();
-        final OperationMetadata      operation = resource.getOperation();
+        final DefaultOperationMetadata operation = resource.getOperation();
         /*
          * Test OperationName replacement when the name matches.
          */
         resource.setOperation(new OperationName(operation.getOperationName()));
         assertNotSame("Before resolve", operation, resource.getOperation());
-        OperationName.resolve(singleton(operation), singleton((CoupledResource) resource));
+        OperationName.resolve(singleton(operation), singleton(resource));
         assertSame("After resolve", operation, resource.getOperation());
         /*
          * If the name doesn't match, no replacement shall be done.
@@ -80,7 +79,7 @@
         final OperationName other = new OperationName("Other");
         resource.setOperation(other);
         assertSame("Before resolve", other, resource.getOperation());
-        OperationName.resolve(singleton(operation), singleton((CoupledResource) resource));
+        OperationName.resolve(singleton(operation), singleton(resource));
         assertSame("After resolve", other, resource.getOperation());
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
index 1373c6b..540cc93 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
@@ -38,7 +38,7 @@
 import static org.apache.sis.test.MetadataAssert.*;
 
 // Branch-specific imports
-import org.apache.sis.internal.jdk7.StandardCharsets;
+import org.opengis.metadata.identification.CharacterSet;
 
 
 /**
@@ -119,7 +119,7 @@
         info.setResourceConstraints(singleton(new DefaultConstraints("Freely available")));
         info.setExtents(singleton(Extents.WORLD));
         info.setLanguages(asList(LOCALES));
-        info.setCharacterSets(singleton(StandardCharsets.US_ASCII));
+        info.setCharacterSets(singleton(CharacterSet.US_ASCII));
         return info;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentificationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentificationTest.java
index b455503..24459df 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentificationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentificationTest.java
@@ -19,7 +19,7 @@
 import javax.xml.bind.JAXBException;
 import org.opengis.util.NameFactory;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.CouplingType;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.xml.NilReason;
@@ -61,7 +61,7 @@
                 "A dummy service for testing purpose.");                // abstract
         id.setServiceTypeVersions(singleton("1.0"));
         id.setCoupledResources(singleton(resource));
-        id.setCouplingType(CouplingType.LOOSE);
+        id.setCouplingType(UnsupportedCodeList.valueOf("LOOSE"));
         id.setContainsOperations(singleton(resource.getOperation()));
         return id;
     }
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 6e0e370..a0ea1af 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.iso.SimpleInternationalString;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.test.LoggingWatcher;
 import org.apache.sis.test.TestCase;
@@ -32,7 +31,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
 public final strictfp class DefaultScopeDescriptionTest extends 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/xml/CharSequenceSubstitutionTest.java b/core/sis-metadata/src/test/java/org/apache/sis/xml/CharSequenceSubstitutionTest.java
index 6aabc71..6cacb58 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/xml/CharSequenceSubstitutionTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/xml/CharSequenceSubstitutionTest.java
@@ -18,7 +18,6 @@
 
 import javax.xml.bind.JAXBException;
 import org.opengis.metadata.citation.Address;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.acquisition.Instrument;
 import org.opengis.metadata.identification.DataIdentification;
 import org.opengis.metadata.identification.InitiativeType;
@@ -30,6 +29,9 @@
 
 import static org.apache.sis.test.Assert.*;
 
+// Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+
 
 /**
  * Tests the XML marshalling of {@code Anchor} and {@code CodeList} as substitution of {@code <gco:CharacterSequence>}.
@@ -62,7 +64,7 @@
                 "  </gmd:codeSpace>\n" +
                 "</gmd:RS_Identifier>";
 
-        final Identifier id = (Identifier) XML.unmarshal(expected);
+        final ReferenceIdentifier id = (ReferenceIdentifier) XML.unmarshal(expected);
         assertEquals("codespace", "L101", id.getCodeSpace());
         assertEquals("code", "EPSG:4326", id.getCode());
     }
diff --git a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/api-changes.properties b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/api-changes.properties
index 6a9e5cc..342be43 100644
--- a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/api-changes.properties
+++ b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/api-changes.properties
@@ -22,3 +22,35 @@
 # with the changes in the international standard. The UML identifiers of added methods are "number"
 # and "numberType" respectively.
 #
+org.opengis.metadata.citation.Citation=-getCollectiveTitle +getGraphics:graphic +getOnlineResources:onlineResource
+org.opengis.metadata.citation.Contact=-getAddress +getAddresses:address +getContactType:contactType -getOnlineResource +getOnlineResources:onlineResource -getPhone +getPhones:phone
+org.opengis.metadata.citation.OnlineResource=+getProtocolRequest:protocolRequest
+org.opengis.metadata.citation.ResponsibleParty=-getContactInfo -getIndividualName -getOrganisationName -getPositionName
+org.opengis.metadata.citation.Telephone=-getFacsimiles +getNumber:number +getNumberType:numberType -getVoices
+org.opengis.metadata.constraint.Constraints=+getConstraintApplicationScope:constraintApplicationScope +getGraphics:graphic +getReferences:reference +getReleasability:releasability +getResponsibleParties:responsibleParty
+org.opengis.metadata.content.Band=+getBoundMax:boundMax +getBoundMin:boundMin +getBoundUnits:boundUnits
+org.opengis.metadata.content.CoverageDescription=+getAttributeGroups:attributeGroup -getContentType -getDimensions +getProcessingLevelCode:processingLevelCode
+org.opengis.metadata.content.FeatureCatalogueDescription=+getFeatureTypeInfo:featureTypes -getFeatureTypes
+org.opengis.metadata.content.RangeDimension=+getDescription:description -getDescriptor +getNames:name
+org.opengis.metadata.distribution.DigitalTransferOptions=+getDistributionFormats:distributionFormat -getOffLine +getOffLines:offLine +getTransferFrequency:transferFrequency
+org.opengis.metadata.distribution.Distribution=+getDescription:description
+org.opengis.metadata.distribution.Format=+getFormatSpecificationCitation:formatSpecificationCitation +getMedia:medium -getName -getSpecification -getVersion
+org.opengis.metadata.distribution.Medium=-getDensities +getDensity:density +getIdentifier:identifier
+org.opengis.metadata.distribution.StandardOrderProcess=+getOrderOptionType:orderOptionType +getOrderOptions:orderOptions
+org.opengis.metadata.ExtendedElementInformation=-getDomainCode +getRationale:rationale -getRationales -getShortName
+org.opengis.metadata.extent.SpatialTemporalExtent=+getVerticalExtent:verticalExtent
+org.opengis.metadata.identification.AggregateInformation=-getAggregateDataSetIdentifier -getAggregateDataSetName +getMetadataReference:metadataReference +getName:name
+org.opengis.metadata.identification.BrowseGraphic=+getImageConstraints:imageContraints +getLinkages:linkage
+org.opengis.metadata.identification.Identification=+getAdditionalDocumentations:additionalDocumentation -getAggregationInfo +getAssociatedResources:associatedResource +getExtents:extent +getProcessingLevel:processingLevel +getSpatialRepresentationTypes:spatialRepresentationType +getSpatialResolutions:spatialResolution ~+getTemporalResolutions:temporalResolution +getTopicCategories:topicCategory
+org.opengis.metadata.identification.Keywords=+getKeywordClass:keywordClass
+org.opengis.metadata.identification.Resolution=+getAngularDistance:angularDistance +getLevelOfDetail:levelOfDetail +getVertical:vertical
+org.opengis.metadata.identification.ServiceIdentification=+getAccessProperties:accessProperties +getContainsChain:containsChain +getContainsOperations:containsOperations +getCoupledResources:coupledResource +getCouplingType:couplingType +getOperatedDatasets:operatedDataset +getOperatesOn:operatesOn +getProfiles:profile +getServiceStandards:serviceStandard +getServiceType:serviceType +getServiceTypeVersions:serviceTypeVersion
+org.opengis.metadata.identification.Usage=+getAdditionalDocumentation:additionalDocumentation +getIdentifiedIssues:identifiedIssues +getResponses:response
+org.opengis.metadata.Identifier=+getCodeSpace:codeSpace +getDescription:description +getVersion:version
+org.opengis.metadata.lineage.Lineage=+getAdditionalDocumentation:additionalDocumentation +getScope:scope
+org.opengis.metadata.lineage.ProcessStep=+getReferences:reference +getScope:scope
+org.opengis.metadata.lineage.Source=-getScaleDenominator +getScope:scope -getSourceExtents +getSourceMetadata:sourceMetadata +getSourceSpatialResolution:sourceSpatialResolution
+org.opengis.metadata.maintenance.MaintenanceInformation=-getDateOfNextUpdate +getMaintenanceDates:maintenanceDate +getMaintenanceScopes:maintenanceScope -getUpdateScopeDescriptions -getUpdateScopes
+org.opengis.metadata.Metadata=+getAlternativeMetadataReferences:alternativeMetadataReference -getCharacterSet +getCharacterSets:characterSet -getDataSetUri -getDateStamp +getDateInfo:dateInfo -getFileIdentifier -getHierarchyLevelNames -getHierarchyLevels -getLanguage +getLanguages:defaultLocale+otherLocale -getLocales +getMetadataIdentifier:metadataIdentifier +getMetadataLinkages:metadataLinkage +getMetadataProfiles:metadataProfile +getMetadataScopes:metadataScope -getMetadataStandardName -getMetadataStandardVersion +getMetadataStandards:metadataStandard -getParentIdentifier +getParentMetadata:parentMetadata +getResourceLineages:resourceLineage
+org.opengis.metadata.quality.Scope=-getExtent +getExtents:extent
+org.opengis.metadata.spatial.Dimension=+getDimensionDescription:dimensionDescription +getDimensionTitle:dimensionTitle
diff --git a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/identification/ServiceIdentification.xml b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/identification/ServiceIdentification.xml
index de9573b..fe52ae1 100644
--- a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/identification/ServiceIdentification.xml
+++ b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/iso/identification/ServiceIdentification.xml
@@ -76,9 +76,6 @@
               </gco:TypeName>
             </gco:attributeType>
           </srv:name>
-          <srv:direction>
-            <srv:SV_ParameterDirection>in</srv:SV_ParameterDirection>
-          </srv:direction>
           <srv:optionality>
             <gco:CharacterString>Optional</gco:CharacterString>
           </srv:optionality>
diff --git a/core/sis-referencing/pom.xml b/core/sis-referencing/pom.xml
index 7d5899a..da6642b 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
   <groupId>org.apache.sis.core</groupId>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
index 6861851..aca2025 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
@@ -24,7 +24,6 @@
 import java.util.Arrays;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.cs.CoordinateSystem;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
index 7ecd707..70958f3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
@@ -27,8 +27,6 @@
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
-import org.opengis.geometry.UnmodifiableGeometryException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.cs.CoordinateSystem;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
index c26d515..6ac9df9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
@@ -26,7 +26,6 @@
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.opengis.referencing.cs.RangeMeaning;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
index b018bd1..a811624 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
@@ -20,7 +20,6 @@
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java
index cce6f0e..87bc4d6 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralEnvelope.java
@@ -31,7 +31,6 @@
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 import org.apache.sis.util.resources.Errors;
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/ImmutableEnvelope.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/ImmutableEnvelope.java
index bc99ec4..8a99f95 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/ImmutableEnvelope.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/ImmutableEnvelope.java
@@ -25,7 +25,6 @@
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.metadata.extent.GeographicBoundingBox;
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/MismatchedReferenceSystemException.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/MismatchedReferenceSystemException.java
new file mode 100644
index 0000000..ce27ce0
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/MismatchedReferenceSystemException.java
@@ -0,0 +1,63 @@
+/*
+ * 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.geometry;
+
+
+/**
+ * Indicates that an object cannot be constructed because of a mismatch in the
+ * {@linkplain org.opengis.referencing.ReferenceSystem reference systems} of
+ * geometric components.
+ *
+ * @author  Martin Desruisseaux (IRD)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public class MismatchedReferenceSystemException extends IllegalArgumentException {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 6222334569692693273L;
+
+    /**
+     * Creates an exception with no message.
+     */
+    public MismatchedReferenceSystemException() {
+        super();
+    }
+
+    /**
+     * Creates an exception with the specified message.
+     *
+     * @param  message The detail message. The detail message is saved for
+     *         later retrieval by the {@link #getMessage()} method.
+     */
+    public MismatchedReferenceSystemException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Creates an exception with the specified message and cause.
+     *
+     * @param  message The detail message. The detail message is saved for
+     *         later retrieval by the {@link #getMessage()} method.
+     * @param  cause The cause.
+     */
+    public MismatchedReferenceSystemException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/UnmodifiableGeometryException.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/UnmodifiableGeometryException.java
new file mode 100644
index 0000000..02410ad
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/UnmodifiableGeometryException.java
@@ -0,0 +1,54 @@
+/*
+ * 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.geometry;
+
+
+/**
+ * Indicates that an operation is not allowed on a {@linkplain Geometry geometry} object
+ * because it is unmodifiable. Note that unmodifiable geometries are not necessarily immutable;
+ * they are just not allowed to be modified through the {@code setFoo(...)} method that
+ * raised this exception. Whatever an unmodifiable geometry is immutable or not is
+ * implementation dependent.
+ *
+ * @author  Martin Desruisseaux (IRD)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public class UnmodifiableGeometryException extends UnsupportedOperationException {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = 8679047625299612669L;
+
+    /**
+     * Creates an exception with no message.
+     */
+    public UnmodifiableGeometryException() {
+        super();
+    }
+
+    /**
+     * Creates an exception with the specified message.
+     *
+     * @param  message The detail message. The detail message is saved for
+     *         later retrieval by the {@link #getMessage()} method.
+     */
+    public UnmodifiableGeometryException(final String message) {
+        super(message);
+    }
+}
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 04d3223..113f4f7 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;
@@ -260,8 +261,8 @@
          */
         final Map<String,Object> merged = new HashMap<String,Object>(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.ALIAS_KEY,       GenericName.class, provided.getAlias(), merged, complete.getName());
+        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,
@@ -455,8 +456,8 @@
     private static NamedIdentifier toNamedIdentifier(final Object name) {
         if (name == null || name.getClass() == NamedIdentifier.class) {
             return (NamedIdentifier) name;
-        } else if (name instanceof Identifier) {
-            return new NamedIdentifier((Identifier) name);
+        } else if (name instanceof ReferenceIdentifier) {
+            return new NamedIdentifier((ReferenceIdentifier) name);
         } else {
             return new NamedIdentifier((GenericName) name);
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CD_ParametricDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CD_ParametricDatum.java
index dd151dc..f19f12e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CD_ParametricDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CD_ParametricDatum.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.referencing;
 
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.referencing.datum.ParametricDatum;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 import org.apache.sis.referencing.datum.DefaultParametricDatum;
 
@@ -32,7 +31,7 @@
  * @version 0.7
  * @module
  */
-public final class CD_ParametricDatum extends PropertyType<CD_ParametricDatum, ParametricDatum> {
+public final class CD_ParametricDatum extends PropertyType<CD_ParametricDatum, DefaultParametricDatum> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -47,14 +46,14 @@
      * @return {@code ParametricDatum.class}
      */
     @Override
-    protected Class<ParametricDatum> getBoundType() {
-        return ParametricDatum.class;
+    protected Class<DefaultParametricDatum> getBoundType() {
+        return DefaultParametricDatum.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private CD_ParametricDatum(final ParametricDatum datum) {
+    private CD_ParametricDatum(final DefaultParametricDatum datum) {
         super(datum);
     }
 
@@ -66,7 +65,7 @@
      * @return A {@code PropertyType} wrapping the given the element.
      */
     @Override
-    protected CD_ParametricDatum wrap(final ParametricDatum datum) {
+    protected CD_ParametricDatum wrap(final DefaultParametricDatum datum) {
         return new CD_ParametricDatum(datum);
     }
 
@@ -79,7 +78,7 @@
      */
     @XmlElement(name = "ParametricDatum")
     public DefaultParametricDatum getElement() {
-        return DefaultParametricDatum.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CS_ParametricCS.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CS_ParametricCS.java
index 4692e0b..f2fe656 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CS_ParametricCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CS_ParametricCS.java
@@ -17,7 +17,6 @@
 package org.apache.sis.internal.jaxb.referencing;
 
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.referencing.cs.ParametricCS;
 import org.apache.sis.referencing.cs.DefaultParametricCS;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 
@@ -31,7 +30,7 @@
  * @version 0.7
  * @module
  */
-public final class CS_ParametricCS extends PropertyType<CS_ParametricCS, ParametricCS> {
+public final class CS_ParametricCS extends PropertyType<CS_ParametricCS, DefaultParametricCS> {
     /**
      * Empty constructor for JAXB only.
      */
@@ -46,14 +45,14 @@
      * @return {@code ParametricCS.class}
      */
     @Override
-    protected Class<ParametricCS> getBoundType() {
-        return ParametricCS.class;
+    protected Class<DefaultParametricCS> getBoundType() {
+        return DefaultParametricCS.class;
     }
 
     /**
      * Constructor for the {@link #wrap} method only.
      */
-    private CS_ParametricCS(final ParametricCS cs) {
+    private CS_ParametricCS(final DefaultParametricCS cs) {
         super(cs);
     }
 
@@ -65,7 +64,7 @@
      * @return A {@code PropertyType} wrapping the given the element.
      */
     @Override
-    protected CS_ParametricCS wrap(final ParametricCS cs) {
+    protected CS_ParametricCS wrap(final DefaultParametricCS cs) {
         return new CS_ParametricCS(cs);
     }
 
@@ -78,7 +77,7 @@
      */
     @XmlElement(name = "ParametricCS")
     public DefaultParametricCS getElement() {
-        return DefaultParametricCS.castOrCopy(metadata);
+        return metadata;
     }
 
     /**
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 6fe3cbb..c7cf8d3 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;
@@ -74,7 +75,7 @@
      *
      * @param identifier The identifier from which to get the values.
      */
-    Code(final Identifier identifier) {
+    Code(final ReferenceIdentifier identifier) {
         code      = identifier.getCode();
         codeSpace = identifier.getCodeSpace();
         String version = identifier.getVersion();
@@ -95,7 +96,7 @@
      *
      * @return The identifier, or {@code null} if none.
      */
-    public Identifier getIdentifier() {
+    public ReferenceIdentifier getIdentifier() {
         String c = code;
         if (c == null) {
             return null;
@@ -163,12 +164,12 @@
      * @param  identifiers The object identifiers, or {@code null} if none.
      * @return The {@code <gml:identifier>} as a {@code Code} instance, or {@code null} if none.
      */
-    public static Code forIdentifiedObject(final Class<?> type, final Iterable<? extends Identifier> identifiers) {
+    public static Code forIdentifiedObject(final Class<?> type, final Iterable<? extends ReferenceIdentifier> identifiers) {
         if (identifiers != null) {
             boolean isHTTP = false;
             boolean isEPSG = false;
-            Identifier fallback = null;
-            for (final Identifier identifier : identifiers) {
+            ReferenceIdentifier fallback = null;
+            for (final ReferenceIdentifier identifier : identifiers) {
                 final String code = identifier.getCode();
                 if (code == null) continue; // Paranoiac check.
                 if (code.regionMatches(true, 0, "urn:", 0, 4)) {
@@ -230,10 +231,12 @@
                             if (authority != null) {
                                 for (final Identifier id : authority.getIdentifiers()) {
                                     if (Constants.EPSG.equalsIgnoreCase(id.getCode())) {
-                                        final String cs = id.getCodeSpace();
-                                        if (cs != null) {
-                                            code.codeSpace = cs;
-                                            break;
+                                        if (id instanceof ReferenceIdentifier) {
+                                            final String cs = ((ReferenceIdentifier) id).getCodeSpace();
+                                            if (cs != null) {
+                                                code.codeSpace = cs;
+                                                break;
+                                            }
                                         }
                                     }
                                 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/RS_Identifier.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/RS_Identifier.java
index ce7168b..6c9b6da 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/RS_Identifier.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/RS_Identifier.java
@@ -17,11 +17,12 @@
 package org.apache.sis.internal.jaxb.referencing;
 
 import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.metadata.Identifier;
 
 
 /**
- * JAXB adapter mapping the GeoAPI {@link Identifier} to an implementation class that can
+ * JAXB adapter mapping the GeoAPI {@link ReferenceIdentifier} to an implementation class that can
  * be marshalled. See the package documentation for more information about JAXB and interfaces.
  *
  * <p>Note that a class of the same name is defined in the {@link org.apache.sis.internal.jaxb.metadata}
@@ -36,7 +37,7 @@
  *   <gml:identifier codeSpace="EPSG">4326</gml:identifier>
  * }
  *
- * If the {@code Identifier} to marshal contains a {@linkplain Identifier#getVersion() version},
+ * If the {@code Identifier} to marshal contains a {@linkplain ReferenceIdentifier#getVersion() version},
  * then this adapter concatenates the version to the codespace in a "URI-like" way like below:
  *
  * {@preformat xml
@@ -58,10 +59,10 @@
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.4
  * @module
  */
-public final class RS_Identifier extends XmlAdapter<Code, Identifier> {
+public final class RS_Identifier extends XmlAdapter<Code, ReferenceIdentifier> {
     /**
      * Substitutes the wrapper value read from an XML stream by the object which will
      * represents the identifier. JAXB calls automatically this method at unmarshalling time.
@@ -70,7 +71,7 @@
      * @return An identifier which represents the value.
      */
     @Override
-    public Identifier unmarshal(final Code value) {
+    public ReferenceIdentifier unmarshal(final Code value) {
         return (value != null) ? value.getIdentifier() : null;
     }
 
@@ -82,7 +83,7 @@
      * @return The adapter for the given metadata.
      */
     @Override
-    public Code marshal(final Identifier value) {
+    public Code marshal(final ReferenceIdentifier value) {
         return (value != null) ? new Code(value) : null;
     }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java
index aa2275a..3f5dd88 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java
@@ -21,7 +21,7 @@
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 
 // Branch-dependent imports
-import org.opengis.geometry.UnmodifiableGeometryException;
+import org.apache.sis.geometry.UnmodifiableGeometryException;
 
 
 /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
index cf67ba9..ae41af2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/GeodeticObjectBuilder.java
@@ -37,7 +37,6 @@
 import org.opengis.referencing.cs.TimeCS;
 import org.opengis.referencing.datum.DatumFactory;
 import org.opengis.referencing.datum.TemporalDatum;
-import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.Conversion;
 import org.apache.sis.internal.metadata.ReferencingServices;
@@ -49,6 +48,9 @@
 import org.apache.sis.referencing.Builder;
 import org.apache.sis.referencing.CommonCRS;
 
+// Branch-dependent import
+import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
+
 
 /**
  * Helper methods for building Coordinate Reference Systems and related objects.
@@ -100,7 +102,7 @@
     /**
      * The factory for Coordinate Operation objects, fetched when first needed.
      */
-    private CoordinateOperationFactory copFactory;
+    private DefaultCoordinateOperationFactory copFactory;
 
     /**
      * Creates a new builder.
@@ -141,7 +143,7 @@
     /**
      * Returns the factory for Coordinate Operation objects. This method fetches the factory when first needed.
      */
-    private CoordinateOperationFactory getCoordinateOperationFactory() {
+    private DefaultCoordinateOperationFactory getCoordinateOperationFactory() {
         if (copFactory == null) {
             copFactory = CoordinateOperations.factory();
         }
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 7bfcc7c..d09c6db 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
@@ -21,7 +21,7 @@
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.metadata.extent.Extent;
 import org.apache.sis.xml.NilReason;
 import org.apache.sis.xml.NilObject;
@@ -54,7 +54,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.
@@ -80,9 +80,9 @@
      * 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 Collection<GenericName>  getAlias()       {return null;}
-    @Override public Set<Identifier>          getIdentifiers() {return null;}
+    @Override public Set<ReferenceIdentifier> getIdentifiers() {return null;}
     @Override public InternationalString      getRemarks()     {return null;}
     @Override public InternationalString      getScope()       {return null;}
     @Override public Extent getDomainOfValidity()              {return null;}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
index 09e40f5..11107b3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
@@ -94,6 +94,13 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.JDK8;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
+import org.apache.sis.referencing.factory.GeodeticObjectFactory;
+import org.apache.sis.referencing.cs.DefaultParametricCS;
+import org.apache.sis.referencing.datum.DefaultParametricDatum;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.DatumFactory;
 
 
 /**
@@ -535,6 +542,77 @@
     }
 
     /**
+     * Creates a parametric CS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate system name, and optionally other properties.
+     * @param  axis        the axis of the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    @Override
+    public CoordinateSystem createParametricCS(final Map<String,?> properties, final CoordinateSystemAxis axis,
+            CSFactory factory) throws FactoryException
+    {
+        if (!(factory instanceof GeodeticObjectFactory)) {
+            factory = DefaultFactories.forBuildin(CSFactory.class, GeodeticObjectFactory.class);
+        }
+        return ((GeodeticObjectFactory) factory).createParametricCS(properties, axis);
+    }
+
+    /**
+     * Creates a parametric datum. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the datum name, and optionally other properties.
+     * @param  factory     the factory to use for creating the datum.
+     * @return a parametric datum using the given name.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    @Override
+    public Datum createParametricDatum(final Map<String,?> properties, DatumFactory factory)
+            throws FactoryException
+    {
+        if (!(factory instanceof GeodeticObjectFactory)) {
+            factory = DefaultFactories.forBuildin(DatumFactory.class, GeodeticObjectFactory.class);
+        }
+        return ((GeodeticObjectFactory) factory).createParametricDatum(properties);
+    }
+
+    /**
+     * Creates a parametric CRS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate reference system name, and optionally other properties.
+     * @param  datum       the parametric datum.
+     * @param  cs          the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate reference system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    @Override
+    public SingleCRS createParametricCRS(final Map<String,?> properties, final Datum datum,
+            final CoordinateSystem cs, CRSFactory factory) throws FactoryException
+    {
+        if (!(factory instanceof GeodeticObjectFactory)) {
+            factory = DefaultFactories.forBuildin(CRSFactory.class, GeodeticObjectFactory.class);
+        }
+        try {
+            return ((GeodeticObjectFactory) factory).createParametricCRS(properties,
+                    (DefaultParametricDatum) datum, (DefaultParametricCS) cs);
+        } catch (ClassCastException e) {
+            throw new InvalidGeodeticParameterException(e.toString(), e);
+        }
+    }
+
+    /**
      * Creates a derived CRS from the information found in a WKT 1 {@code FITTED_CS} element.
      * This coordinate system can not be easily constructed from the information provided by the WKT 1 format.
      * Note that this method is needed only for WKT 1 parsing, since WKT provides enough information for using
@@ -685,6 +763,29 @@
     }
 
     /**
+     * Returns the coordinate operation method for the given classification.
+     * This method checks if the given {@code opFactory} is a SIS implementation
+     * before to fallback on a slower fallback.
+     *
+     * @param  opFactory  The coordinate operation factory to use if it is a SIS implementation.
+     * @param  mtFactory  The math transform factory to use as a fallback.
+     * @param  identifier The name or identifier of the operation method to search.
+     * @return The coordinate operation method for the given name or identifier.
+     * @throws FactoryException if an error occurred which searching for the given method.
+     *
+     * @since 0.6
+     */
+    @Override
+    public OperationMethod getOperationMethod(final CoordinateOperationFactory opFactory,
+            final MathTransformFactory mtFactory, final String identifier) throws FactoryException
+    {
+        if (opFactory instanceof DefaultCoordinateOperationFactory) {
+            ((DefaultCoordinateOperationFactory) opFactory).getOperationMethod(identifier);
+        }
+        return super.getOperationMethod(opFactory, mtFactory, identifier);
+    }
+
+    /**
      * Returns information about the Apache SIS configuration.
      * See super-class for a list of keys.
      *
@@ -707,9 +808,9 @@
                     final String msg = Exceptions.getLocalizedMessage(e, locale);
                     return (msg != null) ? msg : e.toString();
                 }
-                if (authority != null) {
+                if (authority instanceof DefaultCitation) {
                     final OnLineFunction f = OnLineFunction.valueOf(CONNECTION);
-                    for (final OnlineResource res : authority.getOnlineResources()) {
+                    for (final OnlineResource res : ((DefaultCitation) authority).getOnlineResources()) {
                         if (f.equals(res.getFunction())) {
                             final InternationalString i18n = res.getDescription();
                             if (i18n != null) return i18n.toString(locale);
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 d5e1446..2359e36 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
@@ -24,10 +24,10 @@
 import javax.measure.unit.NonSI;
 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;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.measure.Latitude;
 import org.apache.sis.measure.Longitude;
@@ -96,10 +96,10 @@
         ArgumentChecks.ensureNonNull("parameters", parameters);
         final Map<String,Object> properties = new HashMap<String,Object>(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 7c1ddcf..d076a44 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
@@ -32,6 +32,7 @@
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.Projection;
@@ -276,7 +277,7 @@
             final ParameterDescriptor<Double> replacement, final ParameterBuilder builder)
     {
         copyAliases(template, toRename, sameNameAs(toRename, replacement), builder.addName(template.getName()));
-        for (final Identifier id : template.getIdentifiers()) {
+        for (final ReferenceIdentifier id : template.getIdentifiers()) {
             builder.addIdentifier(id);
         }
         return builder;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
index c4f7ce9..5afaa11 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
@@ -21,7 +21,6 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlSchemaType;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.GeneralParameterDescriptor;
@@ -33,13 +32,8 @@
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Debug;
 
-import static org.apache.sis.util.Utilities.deepEquals;
 import static org.apache.sis.internal.jaxb.referencing.CC_GeneralOperationParameter.DEFAULT_OCCURRENCE;
 
-// Branch-dependent imports
-import org.apache.sis.internal.jdk7.Objects;
-
-
 /**
  * Abstract definition of a parameter or group of parameters used by a coordinate operation or a process.
  * This interface combines information provided by Referencing by Coordinates (ISO 19111),
@@ -148,7 +142,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -158,7 +152,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -229,17 +223,6 @@
     }
 
     /**
-     * Returns an indication if the parameter is an input to the service, an output or both.
-     * The default implementation returns {@link ParameterDirection#IN}.
-     *
-     * @return Indication if the parameter is an input or output to the service, or {@code null} if unspecified.
-     */
-    @Override
-    public ParameterDirection getDirection() {
-        return ParameterDirection.IN;
-    }
-
-    /**
      * The minimum number of times that values for this parameter group or parameter are required.
      * A value of 0 means an optional parameter.
      *
@@ -278,9 +261,7 @@
                 default: {
                     final GeneralParameterDescriptor that = (GeneralParameterDescriptor) object;
                     return getMinimumOccurs() == that.getMinimumOccurs() &&
-                           getMaximumOccurs() == that.getMaximumOccurs() &&
-                           Objects.equals(getDirection(), that.getDirection()) &&
-                           deepEquals(getDescription(), that.getDescription(), mode);
+                           getMaximumOccurs() == that.getMaximumOccurs();
                 }
             }
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
index dc21301..fa14a63 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
@@ -134,7 +134,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -144,7 +144,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
index a83448a..eb13f84 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
@@ -24,7 +24,6 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.GeneralParameterDescriptor;
@@ -123,7 +122,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -133,7 +132,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -318,31 +317,6 @@
     }
 
     /**
-     * Returns an indication if all parameters in this group are inputs to the service, outputs or both.
-     * If this group contains parameters with different direction, then this method returns {@code null}.
-     *
-     * @return Indication if all parameters are inputs or outputs to the service, or {@code null} if undetermined.
-     */
-    @Override
-    public ParameterDirection getDirection() {
-        ParameterDirection dir = null;
-        for (final GeneralParameterDescriptor param : descriptors) {
-            final ParameterDirection c = param.getDirection();
-            if (c == null) {
-                return null;
-            }
-            if (c != dir) {
-                if (dir == null) {
-                    dir = c;
-                } else {
-                    return null;
-                }
-            }
-        }
-        return dir;
-    }
-
-    /**
      * Returns all parameters in this group.
      *
      * @return The parameter descriptors in this group.
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 317df52..0ecc364 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
@@ -40,6 +40,7 @@
 import org.opengis.util.GenericName;
 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;
@@ -322,7 +323,7 @@
 
     /**
      * Filters names, aliases and identifiers by their code spaces. If the given array is non-null, then the only names,
-     * aliases and identifiers to be formatted are those having a {@link Identifier#getCodeSpace()},
+     * aliases and identifiers to be formatted are those having a {@link ReferenceIdentifier#getCodeSpace()},
      * {@link ScopedName#head()} or {@link GenericName#scope()} value in the given list, unless no name or alias
      * matches this criterion.
      *
@@ -815,10 +816,10 @@
              * 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) {
+                for (final ReferenceIdentifier candidate : identifiers) {
                     if (candidate != null) { // Paranoiac check.
                         if (isPreferredCodespace(candidate.getCodeSpace())) {
                             identifier = candidate;
@@ -839,7 +840,7 @@
              * in the current row and clear the 'name' locale variable. Otherwise, keep the 'name'
              * locale variable in case we found no alias to format.
              */
-            Identifier name = object.getName();
+            ReferenceIdentifier name = object.getName();
             if (name != null) { // Paranoiac check.
                 final String codespace = name.getCodeSpace();
                 if (isPreferredCodespace(codespace)) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java
index 6aa363f..458c5f0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java
@@ -34,6 +34,7 @@
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.io.wkt.Colors;
 import org.apache.sis.io.wkt.ElementKind;
 import org.apache.sis.util.Characters;
@@ -132,7 +133,7 @@
         values = new ArrayList<Object>(2); // In the vast majority of cases, we will have only one value.
         units  = new ArrayList<Object>(2);
         identifiers = new LinkedHashMap<String,Set<Object>>();
-        Identifier name = object.getName();
+        ReferenceIdentifier name = object.getName();
         if (name != null) { // Paranoiac check.
             final String codespace = name.getCodeSpace();
             if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
@@ -175,9 +176,9 @@
          * Add identifiers (detailed mode only).
          */
         if (!isBrief) {
-            final Collection<? extends Identifier> ids = object.getIdentifiers();
+            final Collection<? extends ReferenceIdentifier> ids = object.getIdentifiers();
             if (ids != null) { // Paranoiac check.
-                for (final Identifier id : ids) {
+                for (final ReferenceIdentifier id : ids) {
                     if (!isDeprecated(id)) {
                         final String codespace = id.getCodeSpace();
                         if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
index 4ffdd82..426aaf0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
@@ -766,8 +766,8 @@
                     try {
                         target = destination.parameter(name);
                     } catch (ParameterNotFoundException cause) {
-                        throw new InvalidParameterNameException(Errors.format(
-                                    Errors.Keys.UnexpectedParameter_1, name), cause, name);
+                        throw (InvalidParameterNameException) new InvalidParameterNameException(Errors.format(
+                                    Errors.Keys.UnexpectedParameter_1, name), name).initCause(cause);
                     }
                 } else {
                     target = (ParameterValue<?>) getOrCreate(destination, name, occurrence);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
index edbcada..f5ef0bb 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
@@ -702,7 +702,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link DefaultParameterDescriptorGroup#getName()}</td>
      *   </tr>
      *   <tr>
@@ -712,7 +712,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link DefaultParameterDescriptorGroup#getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -786,8 +786,8 @@
                     cause = e;
                 }
                 if (indices == null) {
-                    throw new InvalidParameterNameException(Errors.format(
-                                Errors.Keys.UnexpectedParameter_1, name), cause, name);
+                    throw (InvalidParameterNameException) new InvalidParameterNameException(Errors.format(
+                                Errors.Keys.UnexpectedParameter_1, name), name).initCause(cause);
                 }
                 matrix.setElement(indices[0], indices[1], ((ParameterValue<?>) param).doubleValue());
             }
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 274718b..44dbb22 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
@@ -67,6 +67,9 @@
 import static org.apache.sis.internal.util.CollectionsExt.immutableSet;
 
 // Branch-dependent imports
+import org.opengis.referencing.ReferenceIdentifier;
+import org.apache.sis.metadata.iso.DefaultIdentifier;
+import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.internal.jdk7.Objects;
 
 
@@ -111,7 +114,7 @@
  * </ul>
  *
  * <div class="section">Immutability and thread safety</div>
- * 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
@@ -176,7 +179,7 @@
      * @see #getName()
      * @see #getNames()
      */
-    private Identifier name;
+    private ReferenceIdentifier name;
 
     /**
      * An alternative name by which this object is identified, or {@code null} if none.
@@ -198,7 +201,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.
@@ -233,7 +236,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 than a {@link String}.
+     * is already a {@link ReferenceIdentifier} object instead than a {@link String}.
      *
      * <table class="sis">
      *   <caption>Recognized properties (non exhaustive list)</caption>
@@ -244,7 +247,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>
@@ -258,17 +261,17 @@
      *     <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>
      *   <tr>
-     *     <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
+     *     <td>"description"</td>
      *     <td>{@link String}</td>
      *     <td>{@link NamedIdentifier#getDescription()} on the {@linkplain #getName() name}</td>
      *   </tr>
@@ -279,7 +282,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>
@@ -330,8 +333,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);
         }
@@ -360,10 +363,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);
         }
@@ -481,7 +484,7 @@
      * @see IdentifiedObjects#getName(IdentifiedObject, Citation)
      */
     @Override
-    public Identifier getName() {
+    public ReferenceIdentifier getName() {
         return name;
     }
 
@@ -506,7 +509,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.
     }
 
@@ -526,7 +529,14 @@
      */
     @XmlElement(name = "description")
     public InternationalString getDescription() {
-        return (name != null) ? name.getDescription() : null;
+        final ReferenceIdentifier name = getName();
+        if (name instanceof ImmutableIdentifier) {
+            return ((ImmutableIdentifier) name).getDescription();
+        }
+        if (name instanceof DefaultIdentifier) {
+            return ((DefaultIdentifier) name).getDescription();
+        }
+        return null;
     }
 
     /**
@@ -967,7 +977,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);
                 }
@@ -995,7 +1005,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();
     }
 
@@ -1012,7 +1022,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.
@@ -1033,7 +1043,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);
         }
 
@@ -1047,7 +1057,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/AbstractReferenceSystem.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
index c1f5db4..d21d3ed 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java
@@ -23,7 +23,7 @@
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.metadata.extent.Extent;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.util.ComparisonMode;
@@ -125,7 +125,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>
@@ -135,7 +135,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>
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 5d9e4ed..0847aba 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
@@ -43,6 +43,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.JDK8;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -204,7 +205,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.
@@ -226,7 +227,7 @@
         assert verifyParameterizedType(getClass());
         properties  = new HashMap<String,Object>(8);
         aliases     = new ArrayList<GenericName>();  // Will often stay empty (default constructor handles those cases well).
-        identifiers = new ArrayList<Identifier> ();
+        identifiers = new ArrayList<ReferenceIdentifier>();
     }
 
     /**
@@ -273,7 +274,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,8 +322,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);
     }
 
     /**
@@ -371,7 +372,7 @@
      * @since 0.6
      */
     private String getCodeSpace() {
-        return (String) properties.get(Identifier.CODESPACE_KEY);
+        return (String) properties.get(ReferenceIdentifier.CODESPACE_KEY);
     }
 
     /**
@@ -403,7 +404,7 @@
      * @see ImmutableIdentifier#getCodeSpace()
      */
     public B setCodeSpace(final Citation authority, final String codespace) {
-        if (!setProperty(Identifier.CODESPACE_KEY, codespace)) {
+        if (!setProperty(ReferenceIdentifier.CODESPACE_KEY, codespace)) {
             namespace = null;
         }
         setProperty(Identifier.AUTHORITY_KEY, authority);
@@ -419,7 +420,7 @@
      * @since 0.6
      */
     private String getVersion() {
-        return (String) properties.get(Identifier.VERSION_KEY);
+        return (String) properties.get(ReferenceIdentifier.VERSION_KEY);
     }
 
     /**
@@ -440,7 +441,7 @@
      *         once since builder construction or since the last call to a {@code createXXX(…)} method.
      */
     public B setVersion(final String version) {
-        setProperty(Identifier.VERSION_KEY, version);
+        setProperty(ReferenceIdentifier.VERSION_KEY, version);
         return self();
     }
 
@@ -553,7 +554,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 (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, name) != null) {
             // A primary name is already present. Add the given name as an alias instead.
@@ -647,7 +648,7 @@
      * Implementation of {@link #addIdentifier(String)} and {@link #addIdentifier(Citation, String)}.
      */
     private void addIdentifier(final Citation authority, final String codeSpace, final String identifier, final String version) {
-        final Identifier id;
+        final ReferenceIdentifier id;
         if (isDeprecated()) {
             id = new DeprecatedCode(authority, codeSpace, identifier, version, null, getRemarks());
         } else {
@@ -668,7 +669,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();
@@ -698,12 +699,12 @@
      */
     public B addNamesAndIdentifiers(final IdentifiedObject object) {
         ensureNonNull("object", object);
-        for (final Identifier id : object.getIdentifiers()) {
+        for (final ReferenceIdentifier id : object.getIdentifiers()) {
             if (!isDeprecated(id)) {
                 addIdentifier(id);
             }
         }
-        Identifier id = object.getName();
+        ReferenceIdentifier id = object.getName();
         if (!isDeprecated(id)) {
             addName(id);
         }
@@ -816,7 +817,7 @@
      * or {@code null} if none.
      */
     private InternationalString getDescription() {
-        return (InternationalString) properties.get(Identifier.DESCRIPTION_KEY);
+        return (InternationalString) properties.get("description");
     }
 
     /**
@@ -850,7 +851,7 @@
          * Convert to InternationalString now in order to share the same instance if
          * the same description is used both for an Identifier and an IdentifiedObject.
          */
-        properties.put(Identifier.DESCRIPTION_KEY, Types.toInternationalString(description));
+        properties.put("description", Types.toInternationalString(description));
         return self();
     }
 
@@ -946,7 +947,7 @@
         if (cleanup) {
             properties .put(IdentifiedObject.NAME_KEY, null);
             properties .remove(IdentifiedObject.REMARKS_KEY);
-            properties .remove(Identifier.DESCRIPTION_KEY);
+            properties .remove("description");
             properties .remove(AbstractIdentifiedObject.DEPRECATED_KEY);
             aliases    .clear();
             identifiers.clear();
@@ -954,7 +955,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/IdentifiedObjects.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
index 9b2515b..0527890 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
@@ -28,6 +28,7 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.CoordinateOperation;
 
 import org.apache.sis.util.Static;
@@ -650,11 +651,16 @@
         if (identifier == null) {
             return null;
         }
-        String cs = identifier.getCodeSpace();
+        String cs = null;
+        if (identifier instanceof ReferenceIdentifier) {
+            cs = ((ReferenceIdentifier) identifier).getCodeSpace();
+        }
         if (cs == null || cs.isEmpty()) {
             cs = org.apache.sis.internal.util.Citations.getIdentifier(identifier.getAuthority(), true);
         }
-        return NameMeaning.toURN(type, cs, identifier.getVersion(), identifier.getCode());
+        return NameMeaning.toURN(type, cs,
+                (identifier instanceof ReferenceIdentifier) ? ((ReferenceIdentifier) identifier).getVersion() : null,
+                identifier.getCode());
     }
 
     /**
@@ -664,7 +670,7 @@
      * <ul>
      *   <li>If the given identifier implements the {@link GenericName} interface,
      *       then this method delegates to the {@link GenericName#toString()} method.</li>
-     *   <li>Otherwise if the given identifier has a {@linkplain Identifier#getCodeSpace() code space},
+     *   <li>Otherwise if the given identifier has a {@linkplain ReferenceIdentifier#getCodeSpace() code space},
      *       then formats the identifier as "{@code codespace:code}".</li>
      *   <li>Otherwise if the given identifier has an {@linkplain Identifier#getAuthority() authority},
      *       then formats the identifier as "{@code authority:code}".</li>
@@ -691,7 +697,10 @@
             return identifier.toString();
         }
         final String code = identifier.getCode();
-        String cs = identifier.getCodeSpace();
+        String cs = null;
+        if (identifier instanceof ReferenceIdentifier) {
+            cs = ((ReferenceIdentifier) identifier).getCodeSpace();
+        }
         if (cs == null || cs.isEmpty()) {
             cs = org.apache.sis.internal.util.Citations.getIdentifier(identifier.getAuthority(), true);
         }
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 bcc4b45..d93d730 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 @@
  * @version 0.7
  * @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;
             }
         }
@@ -147,8 +147,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) {
@@ -158,7 +158,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 0984679..27703f8 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
@@ -31,6 +31,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;
@@ -119,7 +120,7 @@
      *
      * @param identifier The identifier to copy.
      */
-    public NamedIdentifier(final Identifier identifier) {
+    public NamedIdentifier(final ReferenceIdentifier identifier) {
         super(identifier);
         if (identifier instanceof GenericName) {
             name = (GenericName) identifier;
@@ -135,7 +136,7 @@
      * @param name The name to wrap.
      */
     public NamedIdentifier(final GenericName name) {
-        super(name instanceof Identifier ? (Identifier) name : new NameToIdentifier(name));
+        super(name instanceof ReferenceIdentifier ? (ReferenceIdentifier) name : new NameToIdentifier(name));
         this.name = name;
         isNameSupplied = true;
     }
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 c752140..be4ca3b 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.metadata.quality.PositionalAccuracy;
@@ -126,11 +126,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/AbstractCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
index 10c3e25..4fc345b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
@@ -141,7 +141,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -151,7 +151,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
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 fae4dee..b7c4174 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
@@ -144,7 +144,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/DefaultCompoundCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
index 5aef803..6baba64 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
@@ -151,7 +151,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -161,7 +161,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
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 210bb8b..587a6d0 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
@@ -61,9 +61,8 @@
 import org.apache.sis.util.Classes;
 
 // Branch-dependent imports
-import org.opengis.referencing.cs.ParametricCS;
-import org.opengis.referencing.crs.ParametricCRS;
-import org.opengis.referencing.datum.ParametricDatum;
+import org.apache.sis.referencing.cs.DefaultParametricCS;
+import org.apache.sis.referencing.datum.DefaultParametricDatum;
 
 
 /**
@@ -298,7 +297,7 @@
                 if (WKTKeywords.GeodeticCRS   .equals(type)) return new Geodetic  (properties, (GeodeticCRS)   baseCRS, conversion,                derivedCS);
                 if (WKTKeywords.VerticalCRS   .equals(type)) return new Vertical  (properties, (VerticalCRS)   baseCRS, conversion,   (VerticalCS) derivedCS);
                 if (WKTKeywords.TimeCRS       .equals(type)) return new Temporal  (properties, (TemporalCRS)   baseCRS, conversion,       (TimeCS) derivedCS);
-                if (WKTKeywords.ParametricCRS .equals(type)) return new Parametric(properties, (ParametricCRS) baseCRS, conversion, (ParametricCS) derivedCS);
+                if (WKTKeywords.ParametricCRS .equals(type)) return new Parametric(properties, (ParametricCRS) baseCRS, conversion, (DefaultParametricCS) derivedCS);
                 if (WKTKeywords.EngineeringCRS.equals(type)) {
                     /*
                      * This case may happen for baseCRS of kind GeodeticCRS, ProjectedCRS or EngineeringCRS.
@@ -352,7 +351,7 @@
                 if (WKTKeywords.GeodeticCRS   .equals(type)) return new Geodetic  (properties, (GeodeticCRS)   baseCRS, interpolationCRS, method, baseToDerived,                derivedCS);
                 if (WKTKeywords.VerticalCRS   .equals(type)) return new Vertical  (properties, (VerticalCRS)   baseCRS, interpolationCRS, method, baseToDerived,   (VerticalCS) derivedCS);
                 if (WKTKeywords.TimeCRS       .equals(type)) return new Temporal  (properties, (TemporalCRS)   baseCRS, interpolationCRS, method, baseToDerived,       (TimeCS) derivedCS);
-                if (WKTKeywords.ParametricCRS .equals(type)) return new Parametric(properties, (ParametricCRS) baseCRS, interpolationCRS, method, baseToDerived, (ParametricCS) derivedCS);
+                if (WKTKeywords.ParametricCRS .equals(type)) return new Parametric(properties, (ParametricCRS) baseCRS, interpolationCRS, method, baseToDerived, (DefaultParametricCS) derivedCS);
                 if (WKTKeywords.EngineeringCRS.equals(type)) {
                     if (baseCRS instanceof EngineeringCRS) {
                         // See the comment in create(Map, SingleCRS, Conversion, CoordinateSystem)
@@ -378,7 +377,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) {
                 if (WKTKeywords.GeodeticCRS   .equals(type)) return new Geodetic   (object);
                 if (WKTKeywords.VerticalCRS   .equals(type)) return new Vertical   (object);
@@ -631,7 +630,7 @@
             return WKTKeywords.VerticalCRS;
         } else if (TemporalCRS.class.isAssignableFrom(type) && derivedCS instanceof TimeCS) {
             return WKTKeywords.TimeCRS;
-        } else if (ParametricCRS.class.isAssignableFrom(type) && derivedCS instanceof ParametricCS) {
+        } else if (ParametricCRS.class.isAssignableFrom(type) && derivedCS instanceof DefaultParametricCS) {
             return WKTKeywords.ParametricCRS;
         } else if (ProjectedCRS.class.isAssignableFrom(type) || EngineeringCRS.class.isAssignableFrom(type)) {
             return WKTKeywords.EngineeringCRS;
@@ -813,32 +812,32 @@
         }
 
         /** Creates a new parametric CRS from the given properties. */
-        Parametric(Map<String,?> properties, ParametricCRS baseCRS, Conversion conversion, ParametricCS derivedCS) {
+        Parametric(Map<String,?> properties, ParametricCRS baseCRS, Conversion conversion, DefaultParametricCS derivedCS) {
             super(properties, baseCRS, conversion, derivedCS);
         }
 
         /** Creates a new parametric CRS from the given properties. */
         Parametric(Map<String,?> properties, ParametricCRS baseCRS, CoordinateReferenceSystem interpolationCRS,
-                OperationMethod method, MathTransform baseToDerived, ParametricCS derivedCS)
+                OperationMethod method, MathTransform baseToDerived, DefaultParametricCS derivedCS)
         {
             super(properties, baseCRS, interpolationCRS, method, baseToDerived, derivedCS);
         }
 
         /** Returns the datum of the base parametric CRS. */
-        @Override public ParametricDatum getDatum() {
-            return (ParametricDatum) super.getDatum();
+        @Override public DefaultParametricDatum getDatum() {
+            return (DefaultParametricDatum) super.getDatum();
         }
 
         /** Returns the coordinate system given at construction time. */
-        @Override public ParametricCS getCoordinateSystem() {
-            return (ParametricCS) super.getCoordinateSystem();
+        @Override public DefaultParametricCS getCoordinateSystem() {
+            return (DefaultParametricCS) super.getCoordinateSystem();
         }
 
         /** Returns a coordinate reference system of the same type than this CRS but with different axes. */
         @Override AbstractCRS createSameType(final Map<String,?> properties, final CoordinateSystem derivedCS) {
             final Conversion conversionFromBase = getConversionFromBase();
             return new Parametric(properties, (ParametricCRS) conversionFromBase.getSourceCRS(),
-                    conversionFromBase, (ParametricCS) derivedCS);
+                    conversionFromBase, (DefaultParametricCS) derivedCS);
         }
 
         /** Returns the WKT keyword for this derived CRS type. */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java
index 155f3dd..b900f72 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java
@@ -103,7 +103,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -113,7 +113,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
index b455aad..1a3d6fe 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
@@ -108,7 +108,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -118,7 +118,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
index 24654d7..04a43b8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
@@ -20,7 +20,7 @@
 import java.util.HashMap;
 import java.util.Arrays;
 import javax.xml.bind.annotation.XmlTransient;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
@@ -122,7 +122,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -132,7 +132,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -257,7 +257,7 @@
         if (axis.getMinimumValue() == Longitude.MIN_VALUE &&
             axis.getMaximumValue() == Longitude.MAX_VALUE) // For excluding the AxesConvention.POSITIVE_RANGE case.
         {
-            for (final Identifier identifier : super.getIdentifiers()) {
+            for (final ReferenceIdentifier identifier : super.getIdentifiers()) {
                 if (EPSG.equals(identifier.getCodeSpace())) try {
                     final int i = Arrays.binarySearch(EPSG_CODES, Short.parseShort(identifier.getCode()));
                     if (i >= 0) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java
index fb0a384..6e3ddfd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java
@@ -96,7 +96,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -106,7 +106,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultParametricCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultParametricCRS.java
index bdd8edd..9486ac4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultParametricCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultParametricCRS.java
@@ -30,9 +30,8 @@
 import static org.apache.sis.referencing.crs.AbstractCRS.isBaseCRS;
 
 // Branch-dependent imports
-import org.opengis.referencing.cs.ParametricCS;
-import org.opengis.referencing.crs.ParametricCRS;
-import org.opengis.referencing.datum.ParametricDatum;
+import org.apache.sis.referencing.cs.DefaultParametricCS;
+import org.apache.sis.referencing.datum.DefaultParametricDatum;
 
 
 /**
@@ -79,7 +78,7 @@
      *
      * @see #getDatum()
      */
-    private ParametricDatum datum;
+    private DefaultParametricDatum datum;
 
     /**
      * Creates a coordinate reference system from the given properties, datum and coordinate system.
@@ -126,15 +125,17 @@
      *   </tr>
      * </table>
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter types may be changed to
+     * {@code org.opengis.referencing.datum.ParametricDatum} and {@code org.opengis.referencing.cs.ParametricCS}
+     * Those change are pending GeoAPI revision.</div>
+     *
      * @param properties The properties to be given to the coordinate reference system.
      * @param datum The datum.
      * @param cs The coordinate system.
-     *
-     * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createParametricCRS(Map, ParametricDatum, ParametricCS)
      */
     public DefaultParametricCRS(final Map<String,?> properties,
-                                final ParametricDatum datum,
-                                final ParametricCS    cs)
+                                final DefaultParametricDatum datum,
+                                final DefaultParametricCS cs)
     {
         super(properties, cs);
         ensureNonNull("datum", datum);
@@ -148,54 +149,24 @@
      *
      * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p>
      *
-     * @param crs The coordinate reference system to copy.
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter type may be changed
+     * to {@code org.opengis.referencing.crs.ParametricCRS}. This change is pending GeoAPI revision.</div>
      *
-     * @see #castOrCopy(ParametricCRS)
+     * @param crs The coordinate reference system to copy.
      */
-    protected DefaultParametricCRS(final ParametricCRS crs) {
+    protected DefaultParametricCRS(final DefaultParametricCRS crs) {
         super(crs);
         datum = crs.getDatum();
     }
 
     /**
-     * Returns a SIS coordinate reference system implementation with the same values than the given
-     * arbitrary implementation. If the given object is {@code null}, then this method returns {@code null}.
-     * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
-     * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultParametricCRS castOrCopy(final ParametricCRS object) {
-        return (object == null || object instanceof DefaultParametricCRS)
-                ? (DefaultParametricCRS) object : new DefaultParametricCRS(object);
-    }
-
-    /**
-     * Returns the GeoAPI interface implemented by this class.
-     * The SIS implementation returns {@code ParametricCRS.class}.
-     *
-     * <div class="note"><b>Note for implementors:</b>
-     * Subclasses usually do not need to override this method since GeoAPI does not define {@code ParametricCRS}
-     * sub-interface. Overriding possibility is left mostly for implementors who wish to extend GeoAPI with their
-     * own set of interfaces.</div>
-     *
-     * @return {@code ParametricCRS.class} or a user-defined sub-interface.
-     */
-    @Override
-    public Class<? extends ParametricCRS> getInterface() {
-        return ParametricCRS.class;
-    }
-
-    /**
      * Returns the datum.
      *
      * @return The datum.
      */
     @Override
     @XmlElement(name = "parametricDatum", required = true)
-    public ParametricDatum getDatum() {
+    public DefaultParametricDatum getDatum() {
         return datum;
     }
 
@@ -206,8 +177,8 @@
      */
     @Override
     @XmlElement(name = "parametricCS", required = true)
-    public ParametricCS getCoordinateSystem() {
-        return (ParametricCS) super.getCoordinateSystem();
+    public DefaultParametricCS getCoordinateSystem() {
+        return (DefaultParametricCS) super.getCoordinateSystem();
     }
 
     /**
@@ -225,7 +196,7 @@
      */
     @Override
     final AbstractCRS createSameType(final Map<String,?> properties, final CoordinateSystem cs) {
-        return new DefaultParametricCRS(properties, datum, (ParametricCS) cs);
+        return new DefaultParametricCRS(properties, datum, (DefaultParametricCS) cs);
     }
 
     /**
@@ -280,7 +251,7 @@
      *
      * @see #getDatum()
      */
-    private void setDatum(final ParametricDatum value) {
+    private void setDatum(final DefaultParametricDatum value) {
         if (datum == null) {
             datum = value;
         } else {
@@ -293,7 +264,7 @@
      *
      * @see #getCoordinateSystem()
      */
-    private void setCoordinateSystem(final ParametricCS cs) {
+    private void setCoordinateSystem(final DefaultParametricCS cs) {
         setCoordinateSystem("parametricCS", cs);
     }
 }
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 4900eb3..950a9ff 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
@@ -234,7 +234,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;
     }
 
     /**
@@ -285,7 +285,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/crs/DefaultTemporalCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
index a1d9ccc..e1d6a03 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
@@ -115,7 +115,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -125,7 +125,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java
index ed7127f..d37c1f3 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java
@@ -94,7 +94,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -104,7 +104,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ParametricCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ParametricCRS.java
new file mode 100644
index 0000000..b1adba1
--- /dev/null
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/ParametricCRS.java
@@ -0,0 +1,31 @@
+/*
+ * 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.referencing.crs;
+
+import org.opengis.referencing.crs.SingleCRS;
+
+
+/**
+ * Place-holder for an interface not yet present in GeoAPI 3.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+interface ParametricCRS extends SingleCRS {
+}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
index a71eee3..19277f6 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
@@ -131,7 +131,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>
@@ -141,7 +141,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultAffineCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultAffineCS.java
index 2b192d9..56c5a0b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultAffineCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultAffineCS.java
@@ -86,7 +86,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -96,7 +96,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
index c8189f2..e31cd2c 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCartesianCS.java
@@ -94,7 +94,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -104,7 +104,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java
index 6b3ac5f..e7a9653 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java
@@ -82,7 +82,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -92,7 +92,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
index c5543c9..070a2bd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
@@ -260,7 +260,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>
@@ -270,7 +270,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java
index a366c98..ad721bd 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java
@@ -87,7 +87,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -97,7 +97,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultEllipsoidalCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultEllipsoidalCS.java
index decfbac..bee3897 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultEllipsoidalCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultEllipsoidalCS.java
@@ -87,7 +87,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -97,7 +97,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java
index b26b7bb..5607d91 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java
@@ -85,7 +85,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -95,7 +95,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultParametricCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultParametricCS.java
index 1fbda66..db6186b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultParametricCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultParametricCS.java
@@ -21,9 +21,6 @@
 import javax.xml.bind.annotation.XmlType;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 
-// Branch-dependent imports
-import org.opengis.referencing.cs.ParametricCS;
-
 
 /**
  * A 1-dimensional coordinate system for parametric values or functions.
@@ -55,7 +52,7 @@
  */
 @XmlType(name = "ParametricCSType")
 @XmlRootElement(name = "ParametricCS")
-public class DefaultParametricCS extends AbstractCS implements ParametricCS {
+public class DefaultParametricCS extends AbstractCS {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -121,46 +118,16 @@
      *
      * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p>
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter type may be changed
+     * to {@code org.opengis.referencing.cs.ParametricCS}. This change is pending GeoAPI revision.</div>
+     *
      * @param cs The coordinate system to copy.
-     *
-     * @see #castOrCopy(ParametricCS)
      */
-    protected DefaultParametricCS(final ParametricCS cs) {
+    protected DefaultParametricCS(final DefaultParametricCS cs) {
         super(cs);
     }
 
     /**
-     * Returns a SIS coordinate system implementation with the same values than the given arbitrary implementation.
-     * If the given object is {@code null}, then this method returns {@code null}.
-     * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
-     * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultParametricCS castOrCopy(final ParametricCS object) {
-        return (object == null) || (object instanceof DefaultParametricCS)
-                ? (DefaultParametricCS) object : new DefaultParametricCS(object);
-    }
-
-    /**
-     * Returns the GeoAPI interface implemented by this class.
-     * The SIS implementation returns {@code ParametricCS.class}.
-     *
-     * <div class="note"><b>Note for implementors:</b>
-     * Subclasses usually do not need to override this method since GeoAPI does not define {@code ParametricCS}
-     * sub-interface. Overriding possibility is left mostly for implementors who wish to extend GeoAPI with
-     * their own set of interfaces.</div>
-     *
-     * @return {@code ParametricCS.class} or a user-defined sub-interface.
-     */
-    @Override
-    public Class<? extends ParametricCS> getInterface() {
-        return ParametricCS.class;
-    }
-
-    /**
      * {@inheritDoc}
      *
      * @return {@inheritDoc}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultPolarCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultPolarCS.java
index 178ddde..0d47568 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultPolarCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultPolarCS.java
@@ -87,7 +87,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -97,7 +97,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java
index a30bd62..970a174 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultSphericalCS.java
@@ -90,7 +90,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -100,7 +100,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultTimeCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultTimeCS.java
index 7902f93..69a0429 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultTimeCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultTimeCS.java
@@ -88,7 +88,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -98,7 +98,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultUserDefinedCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultUserDefinedCS.java
index 98b9e6f..03a35db 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultUserDefinedCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultUserDefinedCS.java
@@ -79,7 +79,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -89,7 +89,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultVerticalCS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultVerticalCS.java
index 81c05e4..9bb3ba9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultVerticalCS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultVerticalCS.java
@@ -98,7 +98,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -108,7 +108,7 @@
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
+     *     <td>{@link org.opengis.referencing.ReferenceIdentifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
index f948ddd..8cd0cfe 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
@@ -25,10 +25,10 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.util.iso.Types;
@@ -177,7 +177,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>
@@ -187,7 +187,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
index 8f50dea..8bf71cc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
@@ -27,8 +27,8 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.geometry.DirectPosition2D;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.DoubleDouble;
@@ -199,7 +199,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>
@@ -209,7 +209,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
index 30a2725..45a2e01 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEngineeringDatum.java
@@ -21,7 +21,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.EngineeringDatum;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.io.wkt.Formatter;
@@ -68,7 +68,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>
@@ -78,7 +78,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
index fd2810a..199e462 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
@@ -24,8 +24,8 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
@@ -203,7 +203,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>
@@ -213,7 +213,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
index a40f985..1ccfec9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
@@ -22,7 +22,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.ImageDatum;
 import org.opengis.referencing.datum.PixelInCell;
 import org.apache.sis.internal.metadata.WKTKeywords;
@@ -87,7 +87,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>
@@ -97,7 +97,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultParametricDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultParametricDatum.java
index e2bf795..a26183e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultParametricDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultParametricDatum.java
@@ -23,9 +23,6 @@
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.io.wkt.Formatter;
 
-// Branch-dependent imports
-import org.opengis.referencing.datum.ParametricDatum;
-
 
 /**
  * Defines the origin of a parametric coordinate reference system.
@@ -59,7 +56,7 @@
  */
 @XmlType(name = "ParametricDatumType")
 @XmlRootElement(name = "ParametricDatum")
-public class DefaultParametricDatum extends AbstractDatum implements ParametricDatum {
+public class DefaultParametricDatum extends AbstractDatum {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -134,46 +131,16 @@
      *
      * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p>
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter type may be changed
+     * to {@code org.opengis.referencing.datum.ParametricDatum}. This change is pending GeoAPI revision.</div>
+     *
      * @param datum The datum to copy.
-     *
-     * @see #castOrCopy(ParametricDatum)
      */
-    protected DefaultParametricDatum(final ParametricDatum datum) {
+    protected DefaultParametricDatum(final DefaultParametricDatum datum) {
         super(datum);
     }
 
     /**
-     * Returns a SIS datum implementation with the same values than the given arbitrary implementation.
-     * If the given object is {@code null}, then this method returns {@code null}.
-     * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
-     * Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
-     *
-     * @param  object The object to get as a SIS implementation, or {@code null} if none.
-     * @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 DefaultParametricDatum castOrCopy(final ParametricDatum object) {
-        return (object == null) || (object instanceof DefaultParametricDatum) ?
-                (DefaultParametricDatum) object : new DefaultParametricDatum(object);
-    }
-
-    /**
-     * Returns the GeoAPI interface implemented by this class.
-     * The SIS implementation returns {@code ParametricDatum.class}.
-     *
-     * <div class="note"><b>Note for implementors:</b>
-     * Subclasses usually do not need to override this method since GeoAPI does not define {@code TemporalDatum}
-     * sub-interface. Overriding possibility is left mostly for implementors who wish to extend GeoAPI with their
-     * own set of interfaces.</div>
-     *
-     * @return {@code ParametricDatum.class} or a user-defined sub-interface.
-     */
-    @Override
-    public Class<? extends ParametricDatum> getInterface() {
-        return ParametricDatum.class;
-    }
-
-    /**
      * Formats this datum as a <cite>Well Known Text</cite> {@code ParametricDatum[…]} element.
      *
      * <div class="note"><b>Compatibility note:</b>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
index f0696bc..3ea1a64 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
@@ -25,7 +25,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.apache.sis.referencing.AbstractIdentifiedObject;
@@ -129,7 +129,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>
@@ -139,7 +139,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
index a7101e6..37319d2 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
@@ -25,7 +25,7 @@
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.TemporalDatum;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.internal.jaxb.gml.UniversalTimeAdapter;
@@ -113,7 +113,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>
@@ -123,7 +123,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>
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultVerticalDatum.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
index 3b8d552..6fdee1b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultVerticalDatum.java
@@ -22,7 +22,7 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.VerticalDatum;
 import org.opengis.referencing.datum.VerticalDatumType;
 import org.apache.sis.io.wkt.Formatter;
@@ -114,7 +114,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>
@@ -124,7 +124,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>
@@ -229,7 +229,7 @@
     private VerticalDatumType type() {
         VerticalDatumType t = type;
         if (t == null) {
-            final Identifier name = super.getName();
+            final ReferenceIdentifier name = super.getName();
             type = t = VerticalDatumTypes.guess(name != null ? name.getCode() : null, super.getAlias(), null);
         }
         return t;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
index d21eed4..b5ba6ab 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
@@ -40,6 +40,11 @@
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Debug;
 
+// Branch-dependent imports
+import org.apache.sis.referencing.cs.DefaultParametricCS;
+import org.apache.sis.referencing.crs.DefaultParametricCRS;
+import org.apache.sis.referencing.datum.DefaultParametricDatum;
+
 
 /**
  * Creates geodetic objects from codes defined by an authority.
@@ -400,6 +405,9 @@
      * The default implementation delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
      * If the result can not be casted, then a {@link NoSuchAuthorityCodeException} is thrown.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may be changed
+     * to {@code org.opengis.referencing.crs.ParametricCRS}. This change is pending GeoAPI revision.</div>
+     *
      * @param  code Value allocated by authority.
      * @return The coordinate reference system for the given code.
      * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
@@ -407,8 +415,8 @@
      *
      * @see org.apache.sis.referencing.crs.DefaultParametricCRS
      */
-    public ParametricCRS createParametricCRS(final String code) throws NoSuchAuthorityCodeException, FactoryException {
-        return cast(ParametricCRS.class, createCoordinateReferenceSystem(code), code);
+    public DefaultParametricCRS createParametricCRS(final String code) throws NoSuchAuthorityCodeException, FactoryException {
+        return cast(DefaultParametricCRS.class, createCoordinateReferenceSystem(code), code);
     }
 
     /**
@@ -635,6 +643,9 @@
      * The default implementation delegates to {@link #createDatum(String)} and casts the result.
      * If the result can not be casted, then a {@link NoSuchAuthorityCodeException} is thrown.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may be changed
+     * to {@code org.opengis.referencing.datum.ParametricDatum}. This change is pending GeoAPI revision.</div>
+     *
      * @param  code Value allocated by authority.
      * @return The datum for the given code.
      * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
@@ -642,8 +653,8 @@
      *
      * @see org.apache.sis.referencing.datum.DefaultParametricDatum
      */
-    public ParametricDatum createParametricDatum(final String code) throws NoSuchAuthorityCodeException, FactoryException {
-        return cast(ParametricDatum.class, createDatum(code), code);
+    public DefaultParametricDatum createParametricDatum(final String code) throws NoSuchAuthorityCodeException, FactoryException {
+        return cast(DefaultParametricDatum.class, createDatum(code), code);
     }
 
     /**
@@ -913,6 +924,9 @@
      * The default implementation delegates to {@link #createCoordinateSystem(String)} and casts the result.
      * If the result can not be casted, then a {@link NoSuchAuthorityCodeException} is thrown.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may be changed
+     * to {@code org.opengis.referencing.cs.ParametricCS}. This change is pending GeoAPI revision.</div>
+     *
      * @param  code Value allocated by authority.
      * @return The coordinate system for the given code.
      * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
@@ -920,8 +934,8 @@
      *
      * @see org.apache.sis.referencing.cs.DefaultParametricCS
      */
-    public ParametricCS createParametricCS(final String code) throws NoSuchAuthorityCodeException, FactoryException {
-        return cast(ParametricCS.class, createCoordinateSystem(code), code);
+    public DefaultParametricCS createParametricCS(final String code) throws NoSuchAuthorityCodeException, FactoryException {
+        return cast(DefaultParametricCS.class, createCoordinateSystem(code), code);
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
index d684be8..67be765 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
@@ -1052,17 +1052,21 @@
      *
      * The default implementation creates a {@link DefaultParametricCRS} instance.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the parameter types may be changed to
+     * {@code org.opengis.referencing.datum.ParametricDatum} and {@code org.opengis.referencing.cs.ParametricCS},
+     * and the return type may be changed to {@code org.opengis.referencing.crs.ParametricCRS}.
+     * Those change are pending GeoAPI revision.</div>
+     *
      * @param  properties Name and other properties to give to the new object.
      * @param  datum      The parametric datum to use in created CRS.
      * @param  cs         The parametric coordinate system for the created CRS.
      * @throws FactoryException if the object creation failed.
      *
-     * @see DefaultParametricCRS#DefaultParametricCRS(Map, ParametricDatum, ParametricCS)
+     * @see DefaultParametricCRS#DefaultParametricCRS(Map, DefaultParametricDatum, DefaultParametricCS)
      * @see GeodeticAuthorityFactory#createParametricCRS(String)
      */
-    @Override
-    public ParametricCRS createParametricCRS(final Map<String,?> properties,
-            final ParametricDatum datum, final ParametricCS cs) throws FactoryException
+    public DefaultParametricCRS createParametricCRS(final Map<String,?> properties,
+            final DefaultParametricDatum datum, final DefaultParametricCS cs) throws FactoryException
     {
         final DefaultParametricCRS crs;
         try {
@@ -1077,14 +1081,16 @@
      * Creates a parametric datum.
      * The default implementation creates a {@link DefaultParametricDatum} instance.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may be changed
+     * to {@code org.opengis.referencing.datum.ParametricDatum}. This change is pending GeoAPI revision.</div>
+     *
      * @param  properties Name and other properties to give to the new object.
      * @throws FactoryException if the object creation failed.
      *
      * @see DefaultParametricDatum#DefaultParametricDatum(Map)
      * @see GeodeticAuthorityFactory#createParametricDatum(String)
      */
-    @Override
-    public ParametricDatum createParametricDatum(final Map<String,?> properties)
+    public DefaultParametricDatum createParametricDatum(final Map<String,?> properties)
             throws FactoryException
     {
         final DefaultParametricDatum datum;
@@ -1108,6 +1114,9 @@
      *
      * The default implementation creates a {@link DefaultParametricCS} instance.
      *
+     * <div class="warning"><b>Warning:</b> in a future SIS version, the return type may be changed
+     * to {@code org.opengis.referencing.cs.ParametricCS}. This change is pending GeoAPI revision.</div>
+     *
      * @param  properties Name and other properties to give to the new object.
      * @param  axis The single axis.
      * @throws FactoryException if the object creation failed.
@@ -1115,8 +1124,7 @@
      * @see DefaultParametricCS#DefaultParametricCS(Map, CoordinateSystemAxis)
      * @see GeodeticAuthorityFactory#createParametricCS(String)
      */
-    @Override
-    public ParametricCS createParametricCS(Map<String, ?> properties, CoordinateSystemAxis axis) throws FactoryException {
+    public DefaultParametricCS createParametricCS(Map<String, ?> properties, CoordinateSystemAxis axis) throws FactoryException {
         final DefaultParametricCS cs;
         try {
             cs = new DefaultParametricCS(complete(properties), axis);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 91b8ce8..9453f42 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -123,6 +123,8 @@
 import org.apache.sis.internal.jdk8.JDK8;
 import org.apache.sis.internal.jdk7.AutoCloseable;
 import org.apache.sis.internal.util.StandardDateFormat;
+import org.apache.sis.referencing.cs.DefaultParametricCS;
+import org.apache.sis.referencing.datum.DefaultParametricDatum;
 
 
 /**
@@ -1547,10 +1549,10 @@
                      *   PARAMETRIC CRS
                      * ---------------------------------------------------------------------- */
                     else if (type.equalsIgnoreCase("engineering")) {
-                        final ParametricCS    cs    = owner.createParametricCS   (getString(code, result, 8));
-                        final ParametricDatum datum = owner.createParametricDatum(getString(code, result, 9));
-                        crs = crsFactory.createParametricCRS(createProperties("Coordinate Reference System",
-                                name, epsg, area, scope, remarks, deprecated), datum, cs);
+                        final DefaultParametricCS    cs    = owner.createParametricCS   (getString(code, result, 8));
+                        final DefaultParametricDatum datum = owner.createParametricDatum(getString(code, result, 9));
+                        crs = ReferencingServices.getInstance().createParametricCRS(createProperties("Coordinate Reference System",
+                                name, epsg, area, scope, remarks, deprecated), datum, cs, crsFactory);
                     }
                     /* ----------------------------------------------------------------------
                      *   UNKNOWN CRS
@@ -1702,7 +1704,7 @@
                         datum = datumFactory.createEngineeringDatum(properties);
                     }
                     else if (type.equalsIgnoreCase("parametric")) {
-                        datum = datumFactory.createParametricDatum(properties);
+                        datum = ReferencingServices.getInstance().createParametricDatum(properties, datumFactory);
                     }
                     else {
                         throw new FactoryDataException(error().getString(Errors.Keys.UnknownType_1, type));
@@ -2184,7 +2186,7 @@
                     }
                     else if (type.equalsIgnoreCase(WKTKeywords.parametric)) {
                         switch (dimension) {
-                            case 1: cs = csFactory.createParametricCS(properties, axes[0]); break;
+                            case 1: cs = ReferencingServices.getInstance().createParametricCS(properties, axes[0], csFactory); break;
                         }
                     }
                     else if (type.equalsIgnoreCase(WKTKeywords.linear)) {
@@ -2618,7 +2620,7 @@
                 }
                 final Map<String, Object> properties =
                         createProperties("Coordinate_Operation Parameter", name, epsg, isReversible, deprecated);
-                properties.put(Identifier.DESCRIPTION_KEY, description);
+                properties.put(ImmutableIdentifier.DESCRIPTION_KEY, description);
                 @SuppressWarnings({"unchecked", "rawtypes"})
                 final ParameterDescriptor<?> descriptor = new DefaultParameterDescriptor(properties,
                         1, 1, type, valueDomain, null, null);
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 60d88e5..447ddc3 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
@@ -848,7 +848,7 @@
                  * it is not, try to copy it in such object.
                  */
                 final SingleOperation op;
-                if (subOperation instanceof SingleOperation) {
+                if (SubTypes.isSingleOperation(subOperation)) {
                     op = (SingleOperation) subOperation;
                 } else {
                     op = factorySIS.createSingleOperation(properties,
@@ -946,7 +946,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<String,Object>(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 0276e37..855259f 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
@@ -554,7 +554,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) {
@@ -735,7 +735,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(ReferencingServices.PARAMETERS_KEY, single.getParameterValues());
             if (method == null) {
@@ -746,7 +746,7 @@
                     method = DefaultOperationMethod.redimension(method, sourceDimensions, targetDimensions);
                 } catch (IllegalArgumentException ex) {
                     try {
-                        method = factory.getOperationMethod(method.getName().getCode());
+                        method = factorySIS.getOperationMethod(method.getName().getCode());
                         method = DefaultOperationMethod.redimension(method, sourceDimensions, targetDimensions);
                     } catch (NoSuchIdentifierException se) {
                         // ex.addSuppressed(se) on the JDK7 branch.
@@ -861,7 +861,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);
@@ -1062,10 +1062,10 @@
                 if (descriptor != null) {
                     final Identifier name = descriptor.getName();
                     if (name != null) {
-                        method = factory.getOperationMethod(name.getCode());
+                        method = factorySIS.getOperationMethod(name.getCode());
                     }
                     if (method == null) {
-                        method = factory.createOperationMethod(properties,
+                        method = factorySIS.createOperationMethod(properties,
                                 sourceCRS.getCoordinateSystem().getDimension(),
                                 targetCRS.getCoordinateSystem().getDimension(),
                                 descriptor);
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 d62e6d0..0087486 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
@@ -43,6 +43,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
+import org.opengis.referencing.operation.SingleOperation;
 
 
 /**
@@ -71,7 +72,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
@@ -117,8 +118,10 @@
             throw new IllegalArgumentException(Errors.getResources(properties).getString(
                     Errors.Keys.TooFewOccurrences_2, 2, CoordinateOperation.class));
         }
-        operations      = flattened.toArray(new CoordinateOperation[flattened.size()]);
-        this.operations = UnmodifiableArrayList.wrap(operations);
+        // The array is of kind CoordinateOperation[] on GeoAPI 4.0-M03,
+        // but we have to restrict to SingleOperation[] on GeoAPI 3.x.
+        operations      = flattened.toArray(new SingleOperation[flattened.size()]);
+        this.operations = UnmodifiableArrayList.wrap((SingleOperation[]) operations);
         this.sourceCRS  = operations[0].getSourceCRS();
         this.targetCRS  = operations[operations.length - 1].getTargetCRS();
         checkDimensions(properties);
@@ -299,11 +302,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;
     }
 
@@ -399,6 +408,6 @@
         final List<CoordinateOperation> flattened = new ArrayList<CoordinateOperation>(steps.length);
         initialize(null, steps, flattened, DefaultFactories.forBuildin(MathTransformFactory.class),
                 (coordinateOperationAccuracy == null), (domainOfValidity == null));
-        operations = UnmodifiableArrayList.wrap(flattened.toArray(new CoordinateOperation[flattened.size()]));
+        operations = UnmodifiableArrayList.wrap(flattened.toArray(new SingleOperation[flattened.size()]));
     }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index 3dbc5b2..f2fc6fb 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -268,7 +268,6 @@
      *
      * @see DefaultMathTransformFactory#getOperationMethod(String)
      */
-    @Override
     public OperationMethod getOperationMethod(String name) throws FactoryException {
         name = CharSequences.trimWhitespaces(name);
         ArgumentChecks.ensureNonEmpty("name", name);
@@ -332,7 +331,6 @@
      *
      * @see DefaultOperationMethod#DefaultOperationMethod(Map, Integer, Integer, ParameterDescriptorGroup)
      */
-    @Override
     public OperationMethod createOperationMethod(final Map<String,?> properties,
             final Integer sourceDimensions, final Integer targetDimensions,
             ParameterDescriptorGroup parameters) throws FactoryException
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 ca0738a..8fdfd77 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
@@ -21,6 +21,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 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 
 
 /**
@@ -69,7 +72,7 @@
      *
      * @see #getOperation()
      */
-    private CoordinateOperation operation;
+    private SingleOperation operation;
 
     /**
      * Constructs a single operation from a set of properties.
@@ -107,7 +110,7 @@
     public DefaultPassThroughOperation(final Map<String,?>            properties,
                                        final CoordinateReferenceSystem sourceCRS,
                                        final CoordinateReferenceSystem targetCRS,
-                                       final CoordinateOperation       operation,
+                                       final SingleOperation           operation,
                                        final int firstAffectedOrdinate,
                                        final int numTrailingOrdinates)
     {
@@ -167,15 +170,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 {@link 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;
     }
 
@@ -311,7 +342,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 fc6a58e..59dac7d 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
@@ -26,6 +26,9 @@
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 
+// Branch-dependent imports
+import org.apache.sis.referencing.crs.DefaultParametricCRS;
+
 
 /**
  * Information about the relationship between a source component and a target component
@@ -54,7 +57,7 @@
         {GeodeticCRS.class},
         {VerticalCRS.class, GeodeticCRS.class},
         {TemporalCRS.class},
-        {ParametricCRS.class},
+        {DefaultParametricCRS.class},
         {EngineeringCRS.class},
         {ImageCRS.class}
     };
@@ -65,7 +68,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 0fc74ec..89eaccd 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/projection/NormalizedProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
index e5ae046..d746553 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
@@ -20,7 +20,6 @@
 import java.util.HashMap;
 import java.io.Serializable;
 import java.lang.reflect.Modifier;
-import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
@@ -56,6 +55,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -455,7 +455,7 @@
      */
     static boolean identMatch(final OperationMethod method, final String regex, final String identifier) {
         if (identifier != null) {
-            for (final Identifier id : method.getIdentifiers()) {
+            for (final ReferenceIdentifier id : method.getIdentifiers()) {
                 if (Constants.EPSG.equals(id.getCodeSpace())) {
                     return identifier.equals(id.getCode());
                 }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
index e9bdbf3..7e5a828 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
@@ -93,7 +93,7 @@
             }
             default: throw new IllegalArgumentException(String.valueOf(type));
         }
-        if (type != RECTANGLE) {
+        if (PENDING_NEXT_GEOAPI_RELEASE) {
             validate(envelope);
         }
         return envelope;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java b/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
index 0265105..bcfefbe 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
@@ -55,7 +55,7 @@
      * This is set to {@code true} only when we intentionally want to create an invalid envelope,
      * for example in order to test normalization.
      */
-    boolean skipValidation;
+    boolean skipValidation = !PENDING_NEXT_GEOAPI_RELEASE;
 
     /**
      * Creates a new geographic envelope for the given ordinate values.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroupTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroupTest.java
index fd69ee6..ef3e29a 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroupTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroupTest.java
@@ -199,7 +199,6 @@
                                              final ParameterDescriptor<?> actual)
     {
         assertEquals("name",          expected.getName(),         actual.getName());
-        assertEquals("description",   expected.getDescription(),  actual.getDescription());
         assertEquals("valueClass",    expected.getValueClass(),   actual.getValueClass());
         assertEquals("validValues",   expected.getValidValues(),  actual.getValidValues());
         assertEquals("unit",          expected.getUnit(),         actual.getUnit());
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java
index 1c720ad..a1abef4 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java
@@ -18,7 +18,7 @@
 
 import java.util.Collections;
 import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.simple.SimpleCitation;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
@@ -41,7 +41,7 @@
  */
 public final strictfp class CodeTest extends TestCase {
     /**
-     * Tests the {@link Code#Code(Identifier)} constructor with {@code "EPSG:4326"} identifier.
+     * Tests the {@link Code#Code(ReferenceIdentifier)} constructor with {@code "EPSG:4326"} identifier.
      * This test intentionally uses an identifier with the {@code IOGP} authority instead than
      * EPSG in order to make sure that the {@code codeSpace} attribute is set from
      * {@link Identifier#getCodeSpace()}, not from {@link Identifier#getAuthority()}.
@@ -49,7 +49,7 @@
     @Test
     public void testSimple() {
         final SimpleCitation IOGP = new SimpleCitation("IOGP");
-        final Identifier id = new ImmutableIdentifier(IOGP, "EPSG", "4326");  // See above javadoc.
+        final ReferenceIdentifier id = new ImmutableIdentifier(IOGP, "EPSG", "4326");  // See above javadoc.
         final Code value = new Code(id);
         assertEquals("codeSpace", "EPSG", value.codeSpace);
         assertEquals("code",      "4326", value.code);
@@ -57,7 +57,7 @@
          * Reverse operation. Note that the authority is lost since there is no room for that in a
          * <gml:identifier> element. Current implementation sets the authority to the code space.
          */
-        final Identifier actual = value.getIdentifier();
+        final ReferenceIdentifier actual = value.getIdentifier();
         assertSame  ("authority",  Citations.EPSG, actual.getAuthority());
         assertEquals("codeSpace", "EPSG", actual.getCodeSpace());
         assertNull  ("version",           actual.getVersion());
@@ -65,7 +65,7 @@
     }
 
     /**
-     * Tests the {@link Code#Code(Identifier)} constructor with {@code "EPSG:8.3:4326"} identifier.
+     * Tests the {@link Code#Code(ReferenceIdentifier)} constructor with {@code "EPSG:8.3:4326"} identifier.
      * This test intentionally uses an identifier with the {@code IOGP} authority instead than EPSG
      * for the same reason than {@link #testSimple()}.
      */
@@ -73,7 +73,7 @@
     @DependsOnMethod("testSimple")
     public void testWithVersion() {
         final SimpleCitation IOGP = new SimpleCitation("IOGP");
-        final Identifier id = new ImmutableIdentifier(IOGP, "EPSG", "4326", "8.2", null);  // See above javadoc.
+        final ReferenceIdentifier id = new ImmutableIdentifier(IOGP, "EPSG", "4326", "8.2", null);  // See above javadoc.
         final Code value = new Code(id);
         assertEquals("codeSpace", "EPSG:8.2", value.codeSpace);
         assertEquals("code",      "4326",     value.code);
@@ -81,7 +81,7 @@
          * Reverse operation. Note that the authority is lost since there is no room for that in a
          * <gml:identifier> element. Current implementation sets the authority to the code space.
          */
-        final Identifier actual = value.getIdentifier();
+        final ReferenceIdentifier actual = value.getIdentifier();
         assertSame  ("authority",  Citations.EPSG, actual.getAuthority());
         assertEquals("codeSpace", "EPSG", actual.getCodeSpace());
         assertEquals("version",   "8.2",  actual.getVersion());
@@ -94,7 +94,7 @@
     @Test
     @DependsOnMethod("testWithVersion")
     public void testForIdentifiedObject() {
-        final Identifier id = new ImmutableIdentifier(Citations.EPSG, "EPSG", "4326", "8.2", null);
+        final ReferenceIdentifier id = new ImmutableIdentifier(Citations.EPSG, "EPSG", "4326", "8.2", null);
         final Code value = Code.forIdentifiedObject(GeographicCRS.class, Collections.singleton(id));
         assertNotNull(value);
         assertEquals("codeSpace", Constants.IOGP, value.codeSpace);
@@ -111,7 +111,7 @@
         final DefaultCitation authority = new DefaultCitation("EPSG");
         authority.getIdentifiers().add(new ImmutableIdentifier(null, "OGP", "EPSG"));
 
-        final Identifier id = new ImmutableIdentifier(authority, "EPSG", "4326", "8.2", null);
+        final ReferenceIdentifier id = new ImmutableIdentifier(authority, "EPSG", "4326", "8.2", null);
         final Code value = Code.forIdentifiedObject(GeographicCRS.class, Collections.singleton(id));
         assertNotNull(value);
         assertEquals("codeSpace", "OGP", value.codeSpace);
@@ -129,7 +129,7 @@
         final Code value = new Code();
         value.codeSpace = "OGP";
         value.code = "urn:ogc:def:crs:EPSG:8.2:4326";
-        final Identifier actual = value.getIdentifier();
+        final ReferenceIdentifier actual = value.getIdentifier();
         assertSame  ("authority",  Citations.EPSG, actual.getAuthority());
         assertEquals("codeSpace", "EPSG", actual.getCodeSpace());
         assertEquals("version",   "8.2",  actual.getVersion());
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java
index 8a781f6..32179f5 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java
@@ -82,6 +82,7 @@
         tolerance  = Formulas.ANGULAR_TOLERANCE;
         zTolerance = Formulas.LINEAR_TOLERANCE;
         zDimension = new int[] {2};
+        tolerance  = Formulas.LINEAR_TOLERANCE;                 // Other SIS branches use a stricter threshold.
         createTransform(new CoordinateFrameRotation3D());
         assertFalse(transform instanceof LinearTransform);
         verifyTransform(PositionVector7ParamTest.samplePoint(1),
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java
index 9927f5f..8189204 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.referencing.provider;
 
-import java.util.Arrays;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.datum.Ellipsoid;
@@ -24,12 +23,10 @@
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.referencing.operation.TransformException;
-import org.opengis.test.ToleranceModifier;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.referencing.operation.matrix.Matrix4;
 import org.apache.sis.referencing.operation.transform.CoordinateDomain;
 import org.apache.sis.referencing.operation.transform.EllipsoidToCentricTransform;
@@ -230,6 +227,7 @@
      */
     private void datumShift(final int sourceStep, final int targetStep) throws TransformException {
         tolerance = precision(targetStep);
+        tolerance = Formulas.LINEAR_TOLERANCE;                 // Other SIS branches use a stricter threshold.
         verifyTransform(samplePoint(sourceStep), samplePoint(targetStep));
         validate();
     }
@@ -263,43 +261,11 @@
         derivativeDeltas = new double[] {delta, delta, 100};    // (Δλ, Δφ, Δh)
         zTolerance = Formulas.LINEAR_TOLERANCE / 2;             // Half the precision of h value given by EPSG
         zDimension = new int[] {2};                             // Dimension of h where to apply zTolerance
+        tolerance  = Formulas.LINEAR_TOLERANCE;                 // Other SIS branches use a stricter threshold.
         datumShift(1, 4);
     }
 
     /**
-     * Tests the point used in {@link FranceGeocentricInterpolationTest}. We use this test for making sure
-     * that we get the expected value when using the real geocentric translation method. This test will be
-     * completed by an equivalent test in {@code MolodenskyTransformTest} for verifying the quality of our
-     * approximation.
-     *
-     * @throws FactoryException if an error occurred while creating the transform.
-     * @throws TransformException if transformation of a point failed.
-     *
-     * @see org.apache.sis.referencing.operation.transform.MolodenskyTransformTest#testFranceGeocentricInterpolationPoint()
-     */
-    @Test
-    public void testFranceGeocentricInterpolationPoint() throws FactoryException, TransformException {
-        transform = createDatumShiftForGeographic3D(DefaultFactories.forBuildin(MathTransformFactory.class),
-                 HardCodedDatum.NTF.getEllipsoid(),
-                 CommonCRS.ETRS89.ellipsoid(),
-                -FranceGeocentricInterpolation.TX,
-                -FranceGeocentricInterpolation.TY,
-                -FranceGeocentricInterpolation.TZ);
-
-        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres
-        derivativeDeltas = new double[] {delta, delta, 100};    // (Δλ, Δφ, Δh)
-        tolerance  = FranceGeocentricInterpolationTest.ANGULAR_TOLERANCE;
-        zTolerance = 0.005;             // Half the precision of the target[2] value set below.
-        zDimension = new int[] {2};
-
-        final double[] source   = Arrays.copyOf(FranceGeocentricInterpolationTest.samplePoint(1), 3);
-        final double[] expected = Arrays.copyOf(FranceGeocentricInterpolationTest.samplePoint(2), 3);
-        expected[2] = 43.15;  // Anti-regression (this value is not provided in NTG_88 guidance note).
-        verifyTransform(source, expected);
-        validate();
-    }
-
-    /**
      * Tests conversion of random points.
      *
      * @throws FactoryException if an error occurred while creating the transform.
@@ -310,7 +276,7 @@
     public void testRandomPoints() throws FactoryException, TransformException {
         testGeographicDomain();     // For creating the transform.
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.GEOGRAPHIC;
+//      toleranceModifier = ToleranceModifier.GEOGRAPHIC;
         verifyInDomain(CoordinateDomain.GEOGRAPHIC, 831342815);
     }
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java
index a2e05d8..035747d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2DTest.java
@@ -27,7 +27,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java
index f561baa..4b88f57 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/MapProjectionTest.java
@@ -18,7 +18,7 @@
 
 import java.util.Iterator;
 import org.opengis.util.GenericName;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.apache.sis.metadata.iso.citation.Citations;
@@ -127,8 +127,8 @@
         assertEquals("minimumOccurs", isMandatory ? 1 : 0, actual.getMinimumOccurs());
         if (epsgName != null) {
             for (final GenericName alias : actual.getAlias()) {
-                if (alias instanceof Identifier && ((Identifier) alias).getAuthority() != Citations.EPSG) {
-                    assertOgcIdentifierEquals(ogcName, (Identifier) alias);
+                if (alias instanceof ReferenceIdentifier && ((ReferenceIdentifier) alias).getAuthority() != Citations.EPSG) {
+                    assertOgcIdentifierEquals(ogcName, (ReferenceIdentifier) alias);
                     return;
                 }
             }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java
index 770d618..652e3c0 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NADCONTest.java
@@ -32,7 +32,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Path;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java
index e687abd..53c4ebd 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/NTv2Test.java
@@ -28,7 +28,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Path;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
index dd658c7..eeb7264 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
@@ -138,6 +138,7 @@
         tolerance  = Formulas.ANGULAR_TOLERANCE;
         zTolerance = Formulas.LINEAR_TOLERANCE;
         zDimension = new int[] {2};
+        tolerance  = Formulas.LINEAR_TOLERANCE;                 // Other SIS branches use a stricter threshold.
         createTransform(new PositionVector7Param3D());
         assertFalse(transform instanceof LinearTransform);
         verifyTransform(samplePoint(1), samplePoint(4));
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
index 56cc766..981d7b9 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
@@ -73,8 +73,7 @@
     org.apache.sis.referencing.crs.DefaultCompoundCRSTest.class,
     org.apache.sis.referencing.crs.DefaultEngineeringCRSTest.class,
     org.apache.sis.referencing.crs.DefaultImageCRSTest.class,
-    org.apache.sis.referencing.cs.DirectionAlongMeridianTest.class,
-    org.apache.sis.referencing.factory.GeodeticObjectFactoryTest.class
+    org.apache.sis.referencing.cs.DirectionAlongMeridianTest.class
 })
 public final strictfp class GeodeticObjectParserTest extends TestCase {
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/MathTransformParserTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/MathTransformParserTest.java
index 12b8e87..e26d73b 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/MathTransformParserTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/MathTransformParserTest.java
@@ -30,7 +30,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java
deleted file mode 100644
index c7dab62..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java
+++ /dev/null
@@ -1,700 +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.io.wkt;
-
-import org.opengis.referencing.cs.CoordinateSystem;
-import org.opengis.referencing.crs.CRSFactory;
-import org.opengis.referencing.crs.VerticalCRS;
-import org.opengis.referencing.datum.VerticalDatumType;
-import org.opengis.util.FactoryException;
-import org.opengis.test.wkt.CRSParserTest;
-import org.apache.sis.internal.metadata.AxisNames;
-import org.apache.sis.test.TestRunner;
-import org.apache.sis.test.DependsOn;
-import org.junit.Test;
-import org.junit.Ignore;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-
-/**
- * Tests Well-Known Text parser using the tests defined in GeoAPI. Those tests use the
- * {@link org.apache.sis.referencing.factory.GeodeticObjectFactory#createFromWKT(String)} method.
- *
- * @author  Martin Desruisseaux (IRD, Geomatys)
- * @since   0.6
- * @version 0.7
- * @module
- */
-@RunWith(TestRunner.class)
-@DependsOn(GeodeticObjectParserTest.class)
-public final strictfp class WKTParserTest extends CRSParserTest {
-    /**
-     * Whether the test should replace the curly quotation marks “ and ” by the straight quotation mark ".
-     * The ISO 19162 specification uses only straight quotation marks, but SIS supports both.
-     * Curly quotation marks are convenient for identifying bugs, so we test them first.
-     */
-    private boolean useStraightQuotes;
-
-    /**
-     * Creates a new test case using the default {@code CRSFactory} implementation.
-     */
-    public WKTParserTest() {
-        super(org.apache.sis.internal.system.DefaultFactories.forClass(CRSFactory.class));
-    }
-
-    /**
-     * Pre-process the WKT string before parsing. This method may replace curly quotation marks
-     * ({@code “} and {@code ”}) by straight quotation marks ({@code "}).
-     * The Apache SIS parser should understand both forms transparently.
-     *
-     * @param  wkt The Well-Known Text to pre-process.
-     * @return The Well-Known Text to parse.
-     */
-    @Override
-    protected String preprocessWKT(String wkt) {
-        if (useStraightQuotes) {
-            wkt = super.preprocessWKT(wkt);
-        }
-        return wkt;
-    }
-
-    /**
-     * Verifies the axis names of a geographic CRS. This method is invoked when the parsed object is
-     * expected to have <cite>"Geodetic latitude"</cite> and <cite>"Geodetic longitude"</cite> names.
-     */
-    @SuppressWarnings("fallthrough")
-    private void verifyEllipsoidalCS() {
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        switch (cs.getDimension()) {
-            default: assertEquals("name", AxisNames.ELLIPSOIDAL_HEIGHT, cs.getAxis(2).getName().getCode());
-            case 2:  assertEquals("name", AxisNames.GEODETIC_LONGITUDE, cs.getAxis(1).getName().getCode());
-            case 1:  assertEquals("name", AxisNames.GEODETIC_LATITUDE,  cs.getAxis(0).getName().getCode());
-            case 0:  break;
-        }
-        switch (cs.getDimension()) {
-            default: assertEquals("abbreviation", "h", cs.getAxis(2).getAbbreviation());
-            case 2:  assertEquals("abbreviation", "λ", cs.getAxis(1).getAbbreviation());
-            case 1:  assertEquals("abbreviation", "φ", cs.getAxis(0).getAbbreviation());
-            case 0:  break;
-        }
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   GEODCRS[“WGS 84”,
-     *    DATUM[“World Geodetic System 1984”,
-     *      ELLIPSOID[“WGS 84”, 6378137, 298.257223563,
-     *        LENGTHUNIT[“metre”,1.0]]],
-     *    CS[ellipsoidal,3],
-     *      AXIS[“(lat)”,north,ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      AXIS[“(lon)”,east,ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      AXIS[“ellipsoidal height (h)”,up,LENGTHUNIT[“metre”,1.0]]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testGeographic3D() throws FactoryException {
-        super.testGeographic3D();
-        verifyEllipsoidalCS();
-        useStraightQuotes = true;
-        super.testGeographic3D();                           // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   GEODCRS[“S-95”,
-     *    DATUM[“Pulkovo 1995”,
-     *      ELLIPSOID[“Krassowsky 1940”, 6378245, 298.3,
-     *        LENGTHUNIT[“metre”,1.0]]],
-     *    CS[ellipsoidal,2],
-     *      AXIS[“latitude”,north,ORDER[1]],
-     *      AXIS[“longitude”,east,ORDER[2]],
-     *      ANGLEUNIT[“degree”,0.0174532925199433],
-     *    REMARK[“Система Геодеэических Координвт года 1995(СК-95)”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testGeographicWithUnicode() throws FactoryException {
-        super.testGeographicWithUnicode();
-        verifyEllipsoidalCS();
-        useStraightQuotes = true;
-        super.testGeographicWithUnicode();                  // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   GEODCRS[“NAD83”,
-     *    DATUM[“North American Datum 1983”,
-     *      ELLIPSOID[“GRS 1980”, 6378137, 298.257222101, LENGTHUNIT[“metre”,1.0]]],
-     *    CS[ellipsoidal,2],
-     *      AXIS[“latitude”,north],
-     *      AXIS[“longitude”,east],
-     *      ANGLEUNIT[“degree”,0.017453292519943],
-     *    ID[“EPSG”,4269],
-     *    REMARK[“1986 realisation”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testGeographicWithIdentifier() throws FactoryException {
-        super.testGeographicWithIdentifier();
-        verifyEllipsoidalCS();
-        useStraightQuotes = true;
-        super.testGeographicWithIdentifier();               // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   GEODCRS[“NTF (Paris)”,
-     *    DATUM[“Nouvelle Triangulation Francaise”,
-     *      ELLIPSOID[“Clarke 1880 (IGN)”, 6378249.2, 293.4660213]],
-     *    PRIMEM[“Paris”,2.5969213],
-     *    CS[ellipsoidal,2],
-     *      AXIS[“latitude”,north,ORDER[1]],
-     *      AXIS[“longitude”,east,ORDER[2]],
-     *      ANGLEUNIT[“grad”,0.015707963267949],
-     *    REMARK[“Nouvelle Triangulation Française”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testGeographicWithGradUnits() throws FactoryException {
-        super.testGeographicWithGradUnits();
-        verifyEllipsoidalCS();
-        useStraightQuotes = true;
-        super.testGeographicWithGradUnits();                // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   GEODETICCRS[“JGD2000”,
-     *    DATUM[“Japanese Geodetic Datum 2000”,
-     *      ELLIPSOID[“GRS 1980”, 6378137, 298.257222101]],
-     *    CS[Cartesian,3],
-     *      AXIS[“(X)”,geocentricX],
-     *      AXIS[“(Y)”,geocentricY],
-     *      AXIS[“(Z)”,geocentricZ],
-     *      LENGTHUNIT[“metre”,1.0],
-     *    SCOPE[“Geodesy, topographic mapping and cadastre”],
-     *    AREA[“Japan”],
-     *    BBOX[17.09,122.38,46.05,157.64],
-     *    TIMEEXTENT[2002-04-01,2011-10-21],
-     *    ID[“EPSG”,4946,URI[“urn:ogc:def:crs:EPSG::4946”]],
-     *    REMARK[“注:JGD2000ジオセントリックは現在JGD2011に代わりました。”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testGeocentric() throws FactoryException {
-        super.testGeocentric();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.GEOCENTRIC_X, cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.GEOCENTRIC_Y, cs.getAxis(1).getName().getCode());
-        assertEquals("name", AxisNames.GEOCENTRIC_Z, cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testGeocentric();                             // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Ignored for now, because the Lambert Azimuthal Equal Area projection method is not yet implemented.
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    @Ignore("Lambert Azimuthal Equal Area projection method not yet implemented.")
-    public void testProjectedYX() throws FactoryException {
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   PROJCRS[“NAD27 / Texas South Central”,
-     *    BASEGEODCRS[“NAD27”,
-     *      DATUM[“North American Datum 1927”,
-     *        ELLIPSOID[“Clarke 1866”, 20925832.164, 294.97869821,
-     *          LENGTHUNIT[“US survey foot”,0.304800609601219]]]],
-     *    CONVERSION[“Texas South Central SPCS27”,
-     *      METHOD[“Lambert Conic Conformal (2SP)”,ID[“EPSG”,9802]],
-     *      PARAMETER[“Latitude of false origin”,27.83333333333333,
-     *        ANGLEUNIT[“degree”,0.0174532925199433],ID[“EPSG”,8821]],
-     *      PARAMETER[“Longitude of false origin”,-99.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433],ID[“EPSG”,8822]],
-     *      PARAMETER[“Latitude of 1st standard parallel”,28.383333333333,
-     *        ANGLEUNIT[“degree”,0.0174532925199433],ID[“EPSG”,8823]],
-     *      PARAMETER[“Latitude of 2nd standard parallel”,30.283333333333,
-     *        ANGLEUNIT[“degree”,0.0174532925199433],ID[“EPSG”,8824]],
-     *      PARAMETER[“Easting at false origin”,2000000.0,
-     *        LENGTHUNIT[“US survey foot”,0.304800609601219],ID[“EPSG”,8826]],
-     *      PARAMETER[“Northing at false origin”,0.0,
-     *        LENGTHUNIT[“US survey foot”,0.304800609601219],ID[“EPSG”,8827]]],
-     *    CS[Cartesian,2],
-     *      AXIS[“(x)”,east],
-     *      AXIS[“(y)”,north],
-     *      LENGTHUNIT[“US survey foot”,0.304800609601219],
-     *    REMARK[“Fundamental point: Meade’s Ranch KS, latitude 39°13'26.686"N, longitude 98°32'30.506"W.”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testProjectedWithFootUnits() throws FactoryException {
-        super.testProjectedWithFootUnits();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.EASTING,  cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.NORTHING, cs.getAxis(1).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testProjectedWithFootUnits();                  // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters and the line feed in {@code REMARK}):
-     *
-     * <blockquote><pre>PROJCRS[“NAD83 UTM 10”,
-     *  BASEGEODCRS[“NAD83(86)”,
-     *    DATUM[“North American Datum 1983”,
-     *      ELLIPSOID[“GRS 1980”,6378137,298.257222101]],
-     *    ANGLEUNIT[“degree”,0.0174532925199433],
-     *    PRIMEM[“Greenwich”,0]],
-     *  CONVERSION[“UTM zone 10N”,ID[“EPSG”,16010],
-     *    METHOD[“Transverse Mercator”],
-     *    PARAMETER[“Latitude of natural origin”,0.0],
-     *    PARAMETER[“Longitude of natural origin”,-123.0],
-     *    PARAMETER[“Scale factor”,0.9996],
-     *    PARAMETER[“False easting”,500000.0],
-     *    PARAMETER[“False northing”,0.0]],
-     *  CS[Cartesian,2],
-     *    AXIS[“(E)”,east,ORDER[1]],
-     *    AXIS[“(N)”,north,ORDER[2]],
-     *    LENGTHUNIT[“metre”,1.0],
-     *  REMARK[“In this example units are implied. This is allowed for backward compatibility.
-     *          It is recommended that units are explicitly given in the string,
-     *          as in the previous two examples.”]]</pre></blockquote>
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testProjectedWithImplicitParameterUnits() throws FactoryException {
-        super.testProjectedWithImplicitParameterUnits();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.EASTING,  cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.NORTHING, cs.getAxis(1).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testProjectedWithImplicitParameterUnits();    // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis name and vertical datum type.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   VERTCRS[“NAVD88”,
-     *    VDATUM[“North American Vertical Datum 1988”],
-     *    CS[vertical,1],
-     *      AXIS[“gravity-related height (H)”,up],LENGTHUNIT[“metre”,1.0]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testVertical() throws FactoryException {
-        super.testVertical();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.GRAVITY_RELATED_HEIGHT, cs.getAxis(0).getName().getCode());
-        assertEquals("datumType", VerticalDatumType.GEOIDAL, ((VerticalCRS) object).getDatum().getVerticalDatumType());
-
-        useStraightQuotes = true;
-        super.testVertical();                               // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis name.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   TIMECRS[“GPS Time”,
-     *     TDATUM[“Time origin”,TIMEORIGIN[1980-01-01T00:00:00.0Z]],
-     *     CS[temporal,1],AXIS[“time”,future],TIMEUNIT[“day”,86400.0]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testTemporal() throws FactoryException {
-        super.testTemporal();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.TIME, cs.getAxis(0).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testTemporal();                               // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis name.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   PARAMETRICCRS[“WMO standard atmosphere layer 0”,
-     *     PDATUM[“Mean Sea Level”,ANCHOR[“1013.25 hPa at 15°C”]],
-     *     CS[parametric,1],
-     *     AXIS[“pressure (hPa)”,up],
-     *     PARAMETRICUNIT[“hPa”,100.0]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testParametric() throws FactoryException {
-        super.testParametric();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", "pressure", cs.getAxis(0).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testParametric();                             // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   ENGINEERINGCRS[“Astra Minas Grid”,
-     *    ENGINEERINGDATUM[“Astra Minas”],
-     *    CS[Cartesian,2],
-     *      AXIS[“northing (X)”,north,ORDER[1]],
-     *      AXIS[“westing (Y)”,west,ORDER[2]],
-     *      LENGTHUNIT[“metre”,1.0],
-     *    ID[“EPSG”,5800]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testEngineering() throws FactoryException {
-        super.testEngineering();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.NORTHING, cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.WESTING,  cs.getAxis(1).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testEngineering();                            // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   ENGCRS[“A construction site CRS”,
-     *    EDATUM[“P1”,ANCHOR[“Peg in south corner”]],
-     *    CS[Cartesian,2],
-     *      AXIS[“site east”,southWest,ORDER[1]],
-     *      AXIS[“site north”,southEast,ORDER[2]],
-     *      LENGTHUNIT[“metre”,1.0],
-     *    TIMEEXTENT[“date/time t1”,“date/time t2”]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testEngineeringRotated() throws FactoryException {
-        super.testEngineeringRotated();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", "site east",  cs.getAxis(0).getName().getCode());
-        assertEquals("name", "site north", cs.getAxis(1).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testEngineeringRotated();                     // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *   ENGCRS[“A ship-centred CRS”,
-     *    EDATUM[“Ship reference point”,ANCHOR[“Centre of buoyancy”]],
-     *    CS[Cartesian,3],
-     *      AXIS[“(x)”,forward],
-     *      AXIS[“(y)”,starboard],
-     *      AXIS[“(z)”,down],
-     *      LENGTHUNIT[“metre”,1.0]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testEngineeringForShip() throws FactoryException {
-        super.testEngineeringForShip();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        /*
-         * In this case we had no axis names, so Apache SIS reused the abbreviations.
-         * This could change in any future SIS version if we update Transliterator.
-         */
-        assertEquals("name", "x", cs.getAxis(0).getName().getCode());
-        assertEquals("name", "y", cs.getAxis(1).getName().getCode());
-        assertEquals("name", "z", cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testEngineeringForShip();                     // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *  GEODCRS[“ETRS89 Lambert Azimuthal Equal Area CRS”,
-     *    BASEGEODCRS[“WGS 84”,
-     *      DATUM[“WGS 84”,
-     *        ELLIPSOID[“WGS 84”,6378137,298.2572236,LENGTHUNIT[“metre”,1.0]]]],
-     *    DERIVINGCONVERSION[“Atlantic pole”,
-     *      METHOD[“Pole rotation”,ID[“Authority”,1234]],
-     *      PARAMETER[“Latitude of rotated pole”,52.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      PARAMETER[“Longitude of rotated pole”,-30.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      PARAMETER[“Axis rotation”,-25.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433]]],
-     *    CS[ellipsoidal,2],
-     *      AXIS[“latitude”,north,ORDER[1]],
-     *      AXIS[“longitude”,east,ORDER[2]],
-     *      ANGLEUNIT[“degree”,0.0174532925199433]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testDerivedGeodetic() throws FactoryException {
-        super.testDerivedGeodetic();
-        verifyEllipsoidalCS();
-        useStraightQuotes = true;
-        super.testDerivedGeodetic();                        // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *  ENGCRS[“Topocentric example A”,
-     *    BASEGEODCRS[“WGS 84”,
-     *      DATUM[“WGS 84”,
-     *        ELLIPSOID[“WGS 84”, 6378137, 298.2572236, LENGTHUNIT[“metre”,1.0]]]],
-     *    DERIVINGCONVERSION[“Topocentric example A”,
-     *      METHOD[“Geographic/topocentric conversions”,ID[“EPSG”,9837]],
-     *      PARAMETER[“Latitude of topocentric origin”,55.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      PARAMETER[“Longitude of topocentric origin”,5.0,
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      PARAMETER[“Ellipsoidal height of topocentric origin”,0.0,
-     *        LENGTHUNIT[“metre”,1.0]]],
-     *    CS[Cartesian,3],
-     *      AXIS[“Topocentric East (U)”,east,ORDER[1]],
-     *      AXIS[“Topocentric North (V)”,north,ORDER[2]],
-     *      AXIS[“Topocentric height (W)”,up,ORDER[3]],
-     *      LENGTHUNIT[“metre”,1.0]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testDerivedEngineeringFromGeodetic() throws FactoryException {
-        super.testDerivedEngineeringFromGeodetic();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", "Topocentric East",   cs.getAxis(0).getName().getCode());
-        assertEquals("name", "Topocentric North",  cs.getAxis(1).getName().getCode());
-        assertEquals("name", "Topocentric height", cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testDerivedEngineeringFromGeodetic();         // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testDerivedEngineeringFromProjected() throws FactoryException {
-        super.testDerivedEngineeringFromProjected();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        /*
-         * In this case we had no axis names, so Apache SIS reused the abbreviations.
-         * This could change in any future SIS version if we update Transliterator.
-         */
-        assertEquals("name", "I", cs.getAxis(0).getName().getCode());
-        assertEquals("name", "J", cs.getAxis(1).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testDerivedEngineeringFromProjected();        // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *  COMPOUNDCRS[“NAD83 + NAVD88”,
-     *    GEODCRS[“NAD83”,
-     *      DATUM[“North American Datum 1983”,
-     *        ELLIPSOID[“GRS 1980”,6378137,298.257222101,
-     *          LENGTHUNIT[“metre”,1.0]]],
-     *        PRIMEMERIDIAN[“Greenwich”,0],
-     *      CS[ellipsoidal,2],
-     *        AXIS[“latitude”,north,ORDER[1]],
-     *        AXIS[“longitude”,east,ORDER[2]],
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *      VERTCRS[“NAVD88”,
-     *        VDATUM[“North American Vertical Datum 1988”],
-     *        CS[vertical,1],
-     *          AXIS[“gravity-related height (H)”,up],
-     *          LENGTHUNIT[“metre”,1]]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testCompoundWithVertical() throws FactoryException {
-        super.testCompoundWithVertical();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.GEODETIC_LATITUDE,      cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.GEODETIC_LONGITUDE,     cs.getAxis(1).getName().getCode());
-        assertEquals("name", AxisNames.GRAVITY_RELATED_HEIGHT, cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testCompoundWithVertical();                   // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *  COMPOUNDCRS[“GPS position and time”,
-     *    GEODCRS[“WGS 84”,
-     *      DATUM[“World Geodetic System 1984”,
-     *        ELLIPSOID[“WGS 84”,6378137,298.257223563]],
-     *      CS[ellipsoidal,2],
-     *        AXIS[“(lat)”,north,ORDER[1]],
-     *        AXIS[“(lon)”,east,ORDER[2]],
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *    TIMECRS[“GPS Time”,
-     *      TIMEDATUM[“Time origin”,TIMEORIGIN[1980-01-01]],
-     *      CS[temporal,1],
-     *        AXIS[“time (T)”,future],
-     *        TIMEUNIT[“day”,86400]]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testCompoundWithTime() throws FactoryException {
-        super.testCompoundWithTime();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.GEODETIC_LATITUDE,  cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.GEODETIC_LONGITUDE, cs.getAxis(1).getName().getCode());
-        assertEquals("name", AxisNames.TIME,               cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testCompoundWithTime();                       // Test again with “ and ” replaced by ".
-    }
-
-    /**
-     * Completes the GeoAPI tests with a check of axis names.
-     * The WKT parsed by this test is (except for quote characters):
-     *
-     * {@preformat wkt
-     *  COMPOUNDCRS[“ICAO layer 0”,
-     *    GEODETICCRS[“WGS 84”,
-     *      DATUM[“World Geodetic System 1984”,
-     *        ELLIPSOID[“WGS 84”,6378137,298.257223563,
-     *          LENGTHUNIT[“metre”,1.0]]],
-     *      CS[ellipsoidal,2],
-     *        AXIS[“latitude”,north,ORDER[1]],
-     *        AXIS[“longitude”,east,ORDER[2]],
-     *        ANGLEUNIT[“degree”,0.0174532925199433]],
-     *    PARAMETRICCRS[“WMO standard atmosphere”,
-     *      PARAMETRICDATUM[“Mean Sea Level”,
-     *        ANCHOR[“Mean Sea Level = 1013.25 hPa”]],
-     *          CS[parametric,1],
-     *            AXIS[“pressure (P)”,unspecified],
-     *            PARAMETRICUNIT[“hPa”,100]]]
-     * }
-     *
-     * @throws FactoryException if an error occurred during the WKT parsing.
-     */
-    @Test
-    @Override
-    public void testCompoundWithParametric() throws FactoryException {
-        super.testCompoundWithParametric();
-        final CoordinateSystem cs = object.getCoordinateSystem();
-        assertEquals("name", AxisNames.GEODETIC_LATITUDE,  cs.getAxis(0).getName().getCode());
-        assertEquals("name", AxisNames.GEODETIC_LONGITUDE, cs.getAxis(1).getName().getCode());
-        assertEquals("name", "pressure",                   cs.getAxis(2).getName().getCode());
-
-        useStraightQuotes = true;
-        super.testCompoundWithParametric();                 // Test again with “ and ” replaced by ".
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java b/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
index 3ff38a5..9bc5109 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
@@ -20,7 +20,6 @@
 import java.util.List;
 import java.util.HashMap;
 import java.util.Collections;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.apache.sis.internal.util.Constants;
@@ -104,7 +103,6 @@
      */
     @Test
     public void validateTestObjects() {
-        assertEquals(ParameterDirection.IN, M1_M1_O1_O2.getDirection());
         for (final GeneralParameterDescriptor descriptor : M1_M1_O1_O2.descriptors()) {
             AssertionError error = null;
             try {
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 c9e1139..8219a23 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
@@ -22,10 +22,9 @@
 import javax.measure.unit.SI;
 import javax.measure.unit.Unit;
 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,12 +114,10 @@
     {
         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();}
             @Override public int                      getMinimumOccurs() {return descriptor.getMinimumOccurs();}
             @Override public int                      getMaximumOccurs() {return descriptor.getMaximumOccurs();}
             @Override public Class<T>                 getValueClass()    {return descriptor.getValueClass();}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
index 5b0dfe6..c604819 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
@@ -30,7 +30,6 @@
 import org.junit.Test;
 
 import static java.util.Collections.singletonMap;
-import static org.opengis.test.Validators.validate;
 import static org.apache.sis.test.ReferencingAssert.*;
 import static org.apache.sis.internal.util.Constants.NUM_ROW;
 import static org.apache.sis.internal.util.Constants.NUM_COL;
@@ -321,7 +320,6 @@
                 }
                 final ParameterValueGroup group = param.createValueGroup(
                         singletonMap(ParameterDescriptor.NAME_KEY, "Test"), matrix);
-                validate(group);
                 assertEquals(NUM_ROW,    numRow, group.parameter(NUM_ROW).intValue());
                 assertEquals(NUM_COL,    numCol, group.parameter(NUM_COL).intValue());
                 assertEquals("elements", matrix, param.toMatrix(group));
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 04b9efd..319d5c5 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.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.referencing.datum.AbstractDatum;
 import org.apache.sis.internal.jaxb.referencing.Code;
@@ -57,10 +57,10 @@
      *
      * @param identifier 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<String,Object>(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"));
@@ -77,11 +77,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());
@@ -132,9 +132,9 @@
      */
     @Test
     public void testWithoutIdentifier() {
-        final Set<Identifier>          identifiers = Collections.<Identifier>emptySet();
+        final Set<ReferenceIdentifier> identifiers = Collections.<ReferenceIdentifier>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);
     }
 
@@ -151,10 +151,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());
@@ -168,11 +168,11 @@
     @Test
     @DependsOnMethod("testWithSingleIdentifier")
     public void testWithManyIdentifiers() {
-        final Set<Identifier> identifiers = new LinkedHashSet<Identifier>(4);
+        final Set<ReferenceIdentifier> identifiers = new LinkedHashSet<ReferenceIdentifier>(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());
@@ -186,10 +186,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());
@@ -233,9 +233,9 @@
     @Test
     @DependsOnMethod("testWithoutIdentifier")
     public void testSerialization() {
-        final Set<Identifier>     identifiers = Collections.emptySet();
-        final AbstractIdentifiedObject object = new AbstractIdentifiedObject(properties(identifiers));
-        final AbstractIdentifiedObject actual = assertSerializedEquals(object);
+        final Set<ReferenceIdentifier> identifiers = Collections.emptySet();
+        final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
+        final AbstractIdentifiedObject actual      = assertSerializedEquals(object);
         assertNotSame(object, actual);
         assertNull("gmlId", validate(actual, identifiers, "GRS1980"));
     }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/BuilderTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/BuilderTest.java
index 9cd455a..7fe5569 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/BuilderTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/BuilderTest.java
@@ -24,6 +24,7 @@
 import org.opengis.util.NameFactory;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.SimpleCitation;
 import org.apache.sis.internal.simple.SimpleIdentifier;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -88,17 +89,17 @@
         /*
          * The failed attempt to set a new codespace shall not have modified builder state.
          */
-        assertEquals("EPSG",         builder.properties.get(Identifier.CODESPACE_KEY));
+        assertEquals("EPSG",         builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
         assertSame  (Citations.EPSG, builder.properties.get(Identifier.AUTHORITY_KEY));
         /*
          * After a cleanup (normally after a createXXX(…) method call), user shall be allowed to
          * set a new codespace again. Note that the cleanup operation shall not clear the codespace.
          */
         builder.onCreate(true);
-        assertEquals("EPSG",         builder.properties.get(Identifier.CODESPACE_KEY));
+        assertEquals("EPSG",         builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
         assertSame  (Citations.EPSG, builder.properties.get(Identifier.AUTHORITY_KEY));
         builder.setCodeSpace(IOGP, "EPSG");
-        assertEquals("EPSG", builder.properties.get(Identifier.CODESPACE_KEY));
+        assertEquals("EPSG", builder.properties.get(ReferenceIdentifier.CODESPACE_KEY));
         assertSame  ( IOGP,  builder.properties.get(Identifier.AUTHORITY_KEY));
     }
 
@@ -224,7 +225,7 @@
             { // This is a switch(String) in the JDK7 branch.
                 if (key.equals(Identifier.AUTHORITY_KEY)) {
                     assertSame("Authority and codespace shall be unchanged.", Citations.EPSG, value);
-                } else if (key.equals(Identifier.CODESPACE_KEY)) {
+                } else if (key.equals(ReferenceIdentifier.CODESPACE_KEY)) {
                     assertEquals("Authority and codespace shall be unchanged.", "EPSG", value);
                 } else {
                     assertNull("Should not contain any non-null value except the authority.", value);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java
index c581cc7..76bbd4c 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java
@@ -42,7 +42,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 import static org.apache.sis.test.TestUtilities.*;
 
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/NamedIdentifierTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/NamedIdentifierTest.java
index 5b1c65a..28ed761 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/NamedIdentifierTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/NamedIdentifierTest.java
@@ -17,11 +17,11 @@
 package org.apache.sis.referencing;
 
 import java.util.Locale;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
 import org.opengis.util.NameSpace;
 import org.opengis.util.GenericName;
 import org.opengis.util.NameFactory;
-import org.opengis.metadata.Identifier;
 import org.opengis.test.Validators;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -49,7 +49,7 @@
     @Test
     public void testCreateFromCode() {
         final NamedIdentifier identifier = new NamedIdentifier(Citations.EPSG, "EPSG", "4326", "8.3", null);
-        Validators.validate((Identifier)  identifier);
+        Validators.validate((ReferenceIdentifier) identifier);
         Validators.validate((GenericName) identifier);
 
         // ImmutableIdentifier properties
@@ -75,7 +75,7 @@
         final NameFactory factory = DefaultFactories.forBuildin(NameFactory.class);
         final NameSpace scope = factory.createNameSpace(factory.createLocalName(null, "IOGP"), null);
         final NamedIdentifier identifier = new NamedIdentifier(factory.createGenericName(scope, "EPSG", "4326"));
-        Validators.validate((Identifier)  identifier);
+        Validators.validate((ReferenceIdentifier) identifier);
         Validators.validate((GenericName) identifier);
 
         // ImmutableIdentifier properties
@@ -113,7 +113,7 @@
     @DependsOnMethod("testCreateFromCode")
     public void testCreateFromInternationalString() {
         final NamedIdentifier identifier = createI18N();
-        Validators.validate((Identifier)  identifier);
+        Validators.validate((ReferenceIdentifier) identifier);
         Validators.validate((GenericName) identifier);
 
         // ImmutableIdentifier properties
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
index 7de0f30..238295e 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultDerivedCRSTest.java
@@ -116,7 +116,7 @@
     @Test
     public void testConstruction() {
         final DefaultDerivedCRS crs = createLongitudeRotation();
-        Validators.validate(crs);
+//      Validators.validate(crs);
 
         assertEquals("name",    "Back to Greenwich",                crs.getName().getCode());
         assertEquals("baseCRS", "NTF (Paris)",                      crs.getBaseCRS().getName().getCode());
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
index 61259fb..a2ef8ff 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
@@ -17,10 +17,10 @@
 package org.apache.sis.referencing.crs;
 
 import org.opengis.test.Validators;
-import org.opengis.metadata.Identifier;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.io.wkt.Convention;
@@ -92,7 +92,7 @@
     @Test
     public void testIdentifiers() {
         GeographicCRS crs = CommonCRS.WGS72.geographic();
-        Identifier identifier = getSingleton(crs.getIdentifiers());
+        ReferenceIdentifier identifier = getSingleton(crs.getIdentifiers());
         assertEquals("codespace", "EPSG", identifier.getCodeSpace());
         assertEquals("code",      "4322", identifier.getCode());
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java
index 78363a3..e7336d3 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRSTest.java
@@ -48,8 +48,8 @@
     public void validate() {
         final ValidatorContainer validators = new ValidatorContainer();
         validators.validate(WGS84);
-        validators.validate(WGS84_3D);           validators.crs.enforceStandardNames = false;
-        validators.validate(ELLIPSOIDAL_HEIGHT); validators.crs.enforceStandardNames = true;
+        validators.validate(WGS84_3D);
+        validators.validate(ELLIPSOIDAL_HEIGHT);
         validators.validate(GRAVITY_RELATED_HEIGHT);
         validators.validate(TIME);
         validators.validate(SPHERICAL);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCylindricalCSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCylindricalCSTest.java
index a048b8b..4ee53a4 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCylindricalCSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCylindricalCSTest.java
@@ -25,7 +25,7 @@
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultPolarCSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultPolarCSTest.java
index 98a0845..ab84af0 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultPolarCSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultPolarCSTest.java
@@ -25,7 +25,7 @@
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultSphericalCSTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultSphericalCSTest.java
index c93e70f..d2ebb29 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultSphericalCSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultSphericalCSTest.java
@@ -23,7 +23,7 @@
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2001.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2001.java
deleted file mode 100644
index 6771f55..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2001.java
+++ /dev/null
@@ -1,104 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-import org.apache.sis.util.logging.Logging;
-import org.apache.sis.internal.system.Loggers;
-
-// Test imports
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.referencing.factory.sql.EPSGFactory;
-
-import static org.opengis.test.Assert.*;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createUnit(String)}.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2001 extends org.opengis.test.referencing.gigs.GIGS2001 {
-    /**
-     * The factory instance to use for the tests, or {@code null} if not available.
-     */
-    static EPSGFactory INSTANCE;
-
-    /**
-     * The last failure message logged. Used for avoiding to repeat the same message many times.
-     */
-    private static String failure;
-
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2001() {
-        super(INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        if (INSTANCE == null) try {
-            INSTANCE = new EPSGFactory(null);
-        } catch (UnavailableFactoryException e) {
-            final String message = e.toString();
-            if (!message.equals(failure)) {
-                failure = message;
-                Logging.getLogger(Loggers.CRS_FACTORY).warning(message);
-            }
-            // Leave INSTANCE to null. This will have the effect of skipping tests.
-            return;
-        }
-        assertEquals("Expected no Data Access Object (DAO) before the first test is run.",
-                0, ((ConcurrentAuthorityFactory) INSTANCE).countAvailableDataAccess());
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        if (INSTANCE != null) {
-            final int n = ((ConcurrentAuthorityFactory) INSTANCE).countAvailableDataAccess();
-            INSTANCE.close();
-            // Do not set INSTANCE to null, as it will be reused by other GIGS tests.
-            assertBetween("Since we ran all tests sequantially, should have no more than 1 Data Access Object (DAO).", 0, 1, n);
-        }
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2002.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2002.java
deleted file mode 100644
index d3d7b95..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2002.java
+++ /dev/null
@@ -1,121 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-import org.apache.sis.internal.system.Loggers;
-
-// Test imports
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-import org.apache.sis.test.LoggingWatcher;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createEllipsoid(String)}.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2001.class,     // Units created from EPSG codes
-    GIGS3002.class      // Ellipsoids created from properties
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2002 extends org.opengis.test.referencing.gigs.GIGS2002 {
-    /**
-     * A JUnit {@link Rule} for listening to log events. This field is public because JUnit requires us to
-     * do so, but should be considered as an implementation details (it should have been a private field).
-     */
-    @Rule
-    public final LoggingWatcher loggings = new LoggingWatcher(Loggers.CRS_FACTORY);
-
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2002() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testClarkeMichigan() throws FactoryException {
-        super.testClarkeMichigan();
-        loggings.assertNextLogContains("EPSG:7009");
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testPopularVisualisationSphere() throws FactoryException {
-        super.testPopularVisualisationSphere();
-        loggings.assertNextLogContains("EPSG:7059");
-    }
-
-    /**
-     * Verifies that no unexpected warning has been emitted in this test.
-     */
-    @After
-    public void assertNoUnexpectedLog() {
-        loggings.assertNoUnexpectedLog();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2003.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2003.java
deleted file mode 100644
index e5d9cbe..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2003.java
+++ /dev/null
@@ -1,77 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-
-// Test imports
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createPrimeMeridian(String)}.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2001.class,     // Units created from EPSG codes
-    GIGS3003.class      // Prime meridians created from properties
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2003 extends org.opengis.test.referencing.gigs.GIGS2003 {
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2003() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2004.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2004.java
deleted file mode 100644
index 4594e4b..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2004.java
+++ /dev/null
@@ -1,140 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-import org.opengis.referencing.IdentifiedObject;
-import org.apache.sis.internal.system.Loggers;
-import org.apache.sis.util.CharSequences;
-
-// Test imports
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-import org.apache.sis.test.LoggingWatcher;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateReferenceSystem(String)}
- * for geodetic (geographic or geocentric) CRS.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2002.class,     // Ellipsoids created from EPSG codes
-    GIGS2003.class,     // Prime meridians created from EPSG codes
-    GIGS3004.class      // Geodetic datums created from properties
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2004 extends org.opengis.test.referencing.gigs.GIGS2004 {
-    /**
-     * A JUnit {@link Rule} for listening to log events. This field is public because JUnit requires us to
-     * do so, but should be considered as an implementation details (it should have been a private field).
-     */
-    @Rule
-    public final LoggingWatcher loggings = new LoggingWatcher(Loggers.CRS_FACTORY);
-
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2004() {
-        super(GIGS2001.INSTANCE, GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-
-    /**
-     * Removes the accented characters from the object name, so it can be compared against the expected name.
-     *
-     * @param object The object from which to get a name than can be verified against the expected name.
-     * @return The name of the given object, eventually modified in order to match the expected name.
-     */
-    @Override
-    protected String getVerifiableName(final IdentifiedObject object) {
-        return CharSequences.toASCII(super.getVerifiableName(object)).toString();
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testNAD27_Michigan() throws FactoryException {
-        super.testNAD27_Michigan();
-        loggings.assertNextLogContains("EPSG:6268");    // Datum replaced by 6267
-        loggings.skipNextLogIfContains("EPSG:7009");    // Ellipsoid replaced by 7008 (may have been created by GIGS2002)
-        loggings.assertNextLogContains("EPSG:4268");    // CRS replaced by 4267
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testPopularVisualisation() throws FactoryException {
-        super.testPopularVisualisation();
-        loggings.assertNextLogContains("EPSG:6055");
-        loggings.skipNextLogIfContains("EPSG:7059");    // Ellipsoid may have been created by GIGS2002.
-        loggings.assertNextLogContains("EPSG:4055");
-    }
-
-    /**
-     * Verifies that no unexpected warning has been emitted in this test.
-     */
-    @After
-    public void assertNoUnexpectedLog() {
-        loggings.assertNoUnexpectedLog();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2005.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2005.java
deleted file mode 100644
index 0900097..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2005.java
+++ /dev/null
@@ -1,123 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-import org.apache.sis.internal.system.Loggers;
-
-// Test imports
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-import org.apache.sis.test.LoggingWatcher;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateOperation(String)}
- * for map projections.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2001.class,     // Units created from EPSG codes
-    GIGS3005.class      // Conversions created from properties
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2005 extends org.opengis.test.referencing.gigs.GIGS2005 {
-    /**
-     * A JUnit {@link Rule} for listening to log events. This field is public because JUnit requires us to
-     * do so, but should be considered as an implementation details (it should have been a private field).
-     */
-    @Rule
-    public final LoggingWatcher loggings = new LoggingWatcher(Loggers.CRS_FACTORY);
-
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2005() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testAustralianMapGridZones() throws FactoryException {
-        super.testAustralianMapGridZones();
-        loggings.assertNextLogContains("EPSG:17448");    // Falls outside EEZ area.
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testUSStatePlaneZones_LCC() throws FactoryException {
-        super.testUSStatePlaneZones_LCC();
-        loggings.assertNextLogContains("EPSG:12112");    // Method changed to accord with NGS practice.
-        loggings.assertNextLogContains("EPSG:12113");
-    }
-
-    /**
-     * Verifies that no unexpected warning has been emitted in this test.
-     */
-    @After
-    public void assertNoUnexpectedLog() {
-        loggings.assertNoUnexpectedLog();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2006.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2006.java
deleted file mode 100644
index efe115b..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2006.java
+++ /dev/null
@@ -1,118 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-import org.apache.sis.internal.system.Loggers;
-
-// Test imports
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-import org.apache.sis.test.LoggingWatcher;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateReferenceSystem(String)}
- * for projected CRS.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2004.class,     // Geodetic CRSs created from EPSG codes
-    GIGS2005.class      // Conversions created from EPSG codes
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2006 extends org.opengis.test.referencing.gigs.GIGS2006 {
-    /**
-     * A JUnit {@link Rule} for listening to log events. This field is public because JUnit requires us to
-     * do so, but should be considered as an implementation details (it should have been a private field).
-     */
-    @Rule
-    public final LoggingWatcher loggings = new LoggingWatcher(Loggers.CRS_FACTORY);
-
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2006() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-
-    /**
-     * Overrides the GeoAPI test for verifying the log messages emitted during the construction of deprecated objects.
-     *
-     * @throws FactoryException if an error occurred while creating the object.
-     */
-    @Test
-    @Override
-    public void testNAD27_Michigan() throws FactoryException {
-        super.testNAD27_Michigan();
-        loggings.skipNextLogIfContains("EPSG:6268");     // Datum replaced by 6267
-        loggings.skipNextLogIfContains("EPSG:7009");     // Ellipsoid replaced by 7008
-        loggings.skipNextLogIfContains("EPSG:4268");     // CRS replaced by 4267
-        loggings.assertNextLogContains("EPSG:12111");
-        loggings.assertNextLogContains("EPSG:26811");    // ProjectedCRS (no replacement).
-        loggings.skipNextLogIfContains("EPSG:12112");    // Conversion replaced by 6198
-        loggings.assertNextLogContains("EPSG:26812");    // ProjectedCRS replaced by 6201
-        loggings.skipNextLogIfContains("EPSG:12113");    // Conversion replaced by 6199
-        loggings.assertNextLogContains("EPSG:26813");    // ProjectedCRS replaced by 6202
-    }
-
-    /**
-     * Verifies that no unexpected warning has been emitted in this test.
-     */
-    @After
-    public void assertNoUnexpectedLog() {
-        loggings.assertNoUnexpectedLog();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2007.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2007.java
deleted file mode 100644
index 90a4f22..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2007.java
+++ /dev/null
@@ -1,77 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-
-// Test imports
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateOperation(String)}
- * for horizontal coordinate transformations.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2006.class      // Projected CRSs created from EPSG codes
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2007 extends org.opengis.test.referencing.gigs.GIGS2007 {
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2007() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2008.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2008.java
deleted file mode 100644
index 5ead2a3..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2008.java
+++ /dev/null
@@ -1,77 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-
-// Test imports
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateReferenceSystem(String)}
- * for vertical CRS.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2001.class      // Units created from EPSG codes
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2008 extends org.opengis.test.referencing.gigs.GIGS2008 {
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2008() {
-        super(GIGS2001.INSTANCE, GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2009.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2009.java
deleted file mode 100644
index ac7a5e3..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS2009.java
+++ /dev/null
@@ -1,78 +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.referencing.factory;
-
-import org.opengis.util.FactoryException;
-
-// Test imports
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-import org.apache.sis.test.DependsOn;
-
-
-/**
- * Tests {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#createCoordinateOperation(String)}
- * for vertical coordinate transformations.
- * This is part of <cite>Geospatial Integrity of Geoscience Software</cite> (GIGS) tests implemented in GeoAPI.
- *
- * <div class="note"><b>Note:</b>
- * this test is defined in this package instead than in the {@code sql} sub-package because of the need to access
- * package-private methods in {@link ConcurrentAuthorityFactory}, and for keeping all GIGS tests together.</div>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-@DependsOn({
-    GIGS2008.class      // Vertical CRSs created from EPSG codes
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS2009 extends org.opengis.test.referencing.gigs.GIGS2009 {
-    /**
-     * Creates a new test using the default authority factory.
-     */
-    public GIGS2009() {
-        super(GIGS2001.INSTANCE);
-    }
-
-    /**
-     * Creates the factory to use for all tests in this class.
-     *
-     * @throws FactoryException if an error occurred while creating the factory.
-     */
-    @BeforeClass
-    public static void createFactory() throws FactoryException {
-        GIGS2001.createFactory();
-    }
-
-    /**
-     * Force releases of JDBC connections after the tests in this class.
-     *
-     * @throws FactoryException if an error occurred while closing the connections.
-     */
-    @AfterClass
-    public static void close() throws FactoryException {
-        GIGS2001.close();
-        GIGS2001.INSTANCE = null;       // Since this is the last test of the 2000 series, we can let GC do its work.
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3002.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3002.java
deleted file mode 100644
index ae69128..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3002.java
+++ /dev/null
@@ -1,49 +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.referencing.factory;
-
-import org.opengis.referencing.datum.DatumFactory;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.test.DependsOn;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-
-
-/**
- * Runs the <cite>Geospatial Integrity of Geoscience Software</cite> tests on
- * {@link org.apache.sis.referencing.datum.DefaultEllipsoid} objects creation.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
- * @version 0.6
- * @module
- */
-@DependsOn({
-    org.apache.sis.referencing.datum.DefaultEllipsoidTest.class
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS3002 extends org.opengis.test.referencing.gigs.GIGS3002 {
-    /**
-     * Creates a new test suite using the singleton factory instance.
-     */
-    public GIGS3002() {
-        super(DefaultFactories.forBuildin(DatumFactory.class));
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3003.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3003.java
deleted file mode 100644
index 14e6927..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3003.java
+++ /dev/null
@@ -1,49 +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.referencing.factory;
-
-import org.opengis.referencing.datum.DatumFactory;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.test.DependsOn;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-
-
-/**
- * Runs the <cite>Geospatial Integrity of Geoscience Software</cite> tests on
- * {@link org.apache.sis.referencing.datum.DefaultPrimeMeridian} objects creation.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
- * @version 0.6
- * @module
- */
-@DependsOn({
-    org.apache.sis.referencing.datum.DefaultPrimeMeridianTest.class
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS3003 extends org.opengis.test.referencing.gigs.GIGS3003 {
-    /**
-     * Creates a new test suite using the singleton factory instance.
-     */
-    public GIGS3003() {
-        super(DefaultFactories.forBuildin(DatumFactory.class));
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3004.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3004.java
deleted file mode 100644
index 00859ba..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3004.java
+++ /dev/null
@@ -1,56 +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.referencing.factory;
-
-import org.opengis.referencing.cs.CSFactory;
-import org.opengis.referencing.crs.CRSFactory;
-import org.opengis.referencing.datum.DatumFactory;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.test.DependsOn;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-
-
-/**
- * Runs the <cite>Geospatial Integrity of Geoscience Software</cite> tests on
- * {@link org.apache.sis.referencing.datum.DefaultGeodeticDatum} objects creation.
- * {@code GIGS3004} tests also geographic and geocentric CRS creations with the tested geodetic datum.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
- * @version 0.6
- * @module
- */
-@DependsOn({
-    GIGS3002.class,     // Ellipsoids created from properties
-    GIGS3003.class,     // Prime meridians created from properties
-    org.apache.sis.referencing.datum.DefaultGeodeticDatumTest.class
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS3004 extends org.opengis.test.referencing.gigs.GIGS3004 {
-    /**
-     * Creates a new test suite using the singleton factory instance.
-     */
-    public GIGS3004() {
-        super(DefaultFactories.forBuildin(DatumFactory.class),
-              DefaultFactories.forBuildin(CSFactory.class),
-              DefaultFactories.forBuildin(CRSFactory.class));
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3005.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3005.java
deleted file mode 100644
index afea205..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GIGS3005.java
+++ /dev/null
@@ -1,49 +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.referencing.factory;
-
-import org.opengis.referencing.operation.CoordinateOperationFactory;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.test.DependsOn;
-import org.junit.FixMethodOrder;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.junit.runners.MethodSorters;
-
-
-/**
- * Runs the <cite>Geospatial Integrity of Geoscience Software</cite> tests on
- * {@link org.apache.sis.referencing.operation.DefaultConversion} objects creation.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
- * @version 0.6
- * @module
- */
-@DependsOn({
-    org.apache.sis.referencing.operation.DefaultConversionTest.class
-})
-@RunWith(JUnit4.class)
-@FixMethodOrder(MethodSorters.JVM)      // Intentionally want some randomness
-public final strictfp class GIGS3005 extends org.opengis.test.referencing.gigs.GIGS3005 {
-    /**
-     * Creates a new test suite using the singleton factory instance.
-     */
-    public GIGS3005() {
-        super(DefaultFactories.forBuildin(CoordinateOperationFactory.class));
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
deleted file mode 100644
index 5dbe81e..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
+++ /dev/null
@@ -1,253 +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.referencing.factory;
-
-import java.util.Map;
-import java.util.Collections;
-import javax.measure.unit.SI;
-import javax.measure.unit.Unit;
-import javax.measure.unit.NonSI;
-import javax.measure.quantity.Angle;
-import javax.measure.quantity.Length;
-import org.opengis.util.FactoryException;
-import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.cs.CSFactory;
-import org.opengis.referencing.cs.CartesianCS;
-import org.opengis.referencing.cs.EllipsoidalCS;
-import org.opengis.referencing.cs.AxisDirection;
-import org.opengis.referencing.cs.CoordinateSystemAxis;
-import org.opengis.referencing.crs.CRSFactory;
-import org.opengis.referencing.crs.GeodeticCRS;
-import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.referencing.crs.ProjectedCRS;
-import org.opengis.referencing.datum.DatumFactory;
-import org.opengis.referencing.datum.Ellipsoid;
-import org.opengis.referencing.datum.PrimeMeridian;
-import org.opengis.referencing.datum.GeodeticDatum;
-import org.opengis.referencing.operation.CoordinateOperationFactory;
-import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.Conversion;
-import org.opengis.parameter.ParameterValueGroup;
-import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.referencing.operation.DefaultConversion;
-import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.io.wkt.Convention;
-
-// Test dependencies
-import org.opengis.test.referencing.ObjectFactoryTest;
-import org.apache.sis.test.TestRunner;
-import org.apache.sis.test.DependsOn;
-import org.junit.runner.RunWith;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.apache.sis.test.MetadataAssert.*;
-
-
-/**
- * Tests {@link GeodeticObjectFactory} using the suite of tests provided in the GeoAPI project.
- * Note that this does not include authority factories tests or GIGS tests.
- *
- * @author  Cédric Briançon (Geomatys)
- * @since   0.6
- * @version 0.7
- * @module
- */
-@RunWith(TestRunner.class)
-@DependsOn({
-    org.apache.sis.referencing.crs.DefaultGeocentricCRSTest.class,
-    org.apache.sis.referencing.crs.DefaultGeographicCRSTest.class,
-    org.apache.sis.referencing.crs.DefaultProjectedCRSTest.class
-})
-public final strictfp class GeodeticObjectFactoryTest extends ObjectFactoryTest {
-    /**
-     * Creates a new test suite using the singleton factory instance.
-     */
-    public GeodeticObjectFactoryTest() {
-        super(DefaultFactories.forBuildin(DatumFactory.class),
-              DefaultFactories.forBuildin(CSFactory   .class),
-              DefaultFactories.forBuildin(CRSFactory  .class),
-              DefaultFactories.forBuildin(CoordinateOperationFactory.class));
-    }
-
-    @Override
-    @Deprecated
-    @Ignore("Replaced by testProjectedWithGeoidalHeight()")
-    public void testProjected3D() throws FactoryException {
-    }
-
-    /**
-     * Tests {@link GeodeticObjectFactory#createFromWKT(String)}. We test only a very small WKT here because
-     * it is not the purpose of this class to test the parser. The main purpose of this test is to verify
-     * that {@link GeodeticObjectFactory} has been able to instantiate the parser.
-     *
-     * @throws FactoryException if the parsing failed.
-     */
-    @Test
-    public void testCreateFromWKT() throws FactoryException {
-        final GeodeticCRS crs = (GeodeticCRS) crsFactory.createFromWKT(
-                "GEOGCS[“WGS 84”,\n" +
-                "  DATUM[“World Geodetic System 1984”,\n" +
-                "    SPHEROID[“WGS84”, 6378137.0, 298.257223563]],\n" +
-                "  PRIMEM[“Greenwich”, 0.0],\n" +
-                "  UNIT[“degree”, 0.017453292519943295]]");
-
-        assertEquals("name",  "WGS 84", crs.getName().getCode());
-        assertEquals("datum", "World Geodetic System 1984", crs.getDatum().getName().getCode());
-    }
-
-    /**
-     * Tests {@link GeodeticObjectFactory#createFromWKT(String)} with an erroneous projection parameter name.
-     * The intend is to verify that the expected exception is thrown.
-     *
-     * @throws FactoryException if the parsing failed for another reason than the expected one.
-     */
-    @Test
-    public void testInvalidParameterInWKT() throws FactoryException {
-        try {
-            crsFactory.createFromWKT(
-                "PROJCRS[“Custom”,\n" +
-                "  BASEGEODCRS[“North American 1983”,\n" +
-                "    DATUM[“North American 1983”,\n" +
-                "      ELLIPSOID[“GRS 1980”, 6378137, 298.257222101]]],\n" +
-                "  CONVERSION[“Custom”,\n" +
-                "    METHOD[“Lambert Conformal Conic”],\n" +
-                "    PARAMETER[“Standard parallel 1”, 43.0],\n" +
-                "    PARAMETER[“Standard parallel 2”, 45.5],\n" +
-                "    PARAMETER[“Central parallel”, 41.75]],\n" +       // Wrong parameter.
-                "  CS[Cartesian, 2],\n" +
-                "    AXIS[“(Y)”, north],\n" +
-                "    AXIS[“(X)”, east]]");
-            fail("Should not have parsed a WKT with wrong projection parameter.");
-        } catch (InvalidGeodeticParameterException e) {
-            final String message = e.getMessage();
-            assertTrue(message, message.contains("Central parallel"));
-        }
-    }
-
-    /**
-     * Convenience method creating a map with only the "{@code name"} property.
-     * This is the only mandatory property for object creation.
-     */
-    private static Map<String,?> name(final String name) {
-        return Collections.singletonMap(IdentifiedObject.NAME_KEY, name);
-    }
-
-    /**
-     * Tests step-by-step the creation of a new projected coordinate reference systems.
-     * This test creates every objects itself and compares with expected WKT 1 after each step.
-     *
-     * <p>Note that practical applications may use existing constants declared in the
-     * {@link CommonCRS} class instead than creating everything like this test does.</p>
-     *
-     * @throws FactoryException if the creation of a geodetic component failed.
-     *
-     * @since 0.7
-     */
-    @Test
-    public void testStepByStepCreation() throws FactoryException {
-        /*
-         * List of all objects to be created in this test.
-         */
-        final Unit<Length>         linearUnit;
-        final Unit<Angle>          angularUnit;
-        final Ellipsoid            ellipsoid;
-        final PrimeMeridian        meridian;
-        final GeodeticDatum        datum;
-        final CoordinateSystemAxis longitude, latitude, easting, northing;
-        final EllipsoidalCS        geographicCS;
-        final GeographicCRS        geographicCRS;
-        final OperationMethod      method;
-        final ParameterValueGroup  parameters;
-        final Conversion           projection;
-        final CartesianCS          projectedCS;
-        final ProjectedCRS         projectedCRS;
-        /*
-         * Prime meridian
-         */
-        angularUnit = NonSI.DEGREE_ANGLE;
-        meridian = datumFactory.createPrimeMeridian(name("Greenwich"), 0, angularUnit);
-        assertWktEquals(Convention.WKT1,
-                "PRIMEM[“Greenwich”, 0.0]", meridian);
-        /*
-         * Ellipsoid
-         */
-        linearUnit = SI.METRE;
-        ellipsoid = datumFactory.createEllipsoid(name("Airy1830"), 6377563.396, 6356256.910, linearUnit);
-        assertWktEquals(Convention.WKT1,
-                "SPHEROID[“Airy1830”, 6377563.396, 299.3249753150345]", ellipsoid);
-        /*
-         * Geodetic datum
-         */
-        datum = datumFactory.createGeodeticDatum(name("Airy1830"), ellipsoid, meridian);
-        assertWktEquals(Convention.WKT1,
-                "DATUM[“Airy1830”,\n" +
-                "  SPHEROID[“Airy1830”, 6377563.396, 299.3249753150345]]", datum);
-        /*
-         * Base coordinate reference system
-         */
-        longitude     =  csFactory.createCoordinateSystemAxis(name("Longitude"), "long", AxisDirection.EAST,  angularUnit);
-        latitude      =  csFactory.createCoordinateSystemAxis(name("Latitude"),  "lat",  AxisDirection.NORTH, angularUnit);
-        geographicCS  =  csFactory.createEllipsoidalCS(name("Ellipsoidal"), longitude, latitude);
-        geographicCRS = crsFactory.createGeographicCRS(name("Airy1830"), datum, geographicCS);
-        assertWktEquals(Convention.WKT1,
-                "GEOGCS[“Airy1830”,\n" +
-                "  DATUM[“Airy1830”,\n" +
-                "    SPHEROID[“Airy1830”, 6377563.396, 299.3249753150345]],\n" +
-                "    PRIMEM[“Greenwich”, 0.0],\n" +
-                "  UNIT[“degree”, 0.017453292519943295],\n" +
-                "  AXIS[“Longitude”, EAST],\n" +
-                "  AXIS[“Latitude”, NORTH]]", geographicCRS);
-        /*
-         * Defining conversion
-         */
-        method = copFactory.getOperationMethod("Transverse_Mercator");
-        parameters = method.getParameters().createValue();
-        parameters.parameter("semi_major")        .setValue(ellipsoid.getSemiMajorAxis());
-        parameters.parameter("semi_minor")        .setValue(ellipsoid.getSemiMinorAxis());
-        parameters.parameter("central_meridian")  .setValue(     49);
-        parameters.parameter("latitude_of_origin").setValue(     -2);
-        parameters.parameter("false_easting")     .setValue( 400000);
-        parameters.parameter("false_northing")    .setValue(-100000);
-        projection = new DefaultConversion(name("GBN grid"), method, null, parameters);
-        /*
-         * Projected coordinate reference system
-         */
-        easting      =  csFactory.createCoordinateSystemAxis(name("Easting"),  "x", AxisDirection.EAST,  linearUnit);
-        northing     =  csFactory.createCoordinateSystemAxis(name("Northing"), "y", AxisDirection.NORTH, linearUnit);
-        projectedCS  =  csFactory.createCartesianCS(name("Cartesian"), easting, northing);
-        projectedCRS = crsFactory.createProjectedCRS(name("Great_Britian_National_Grid"), geographicCRS, projection, projectedCS);
-        assertWktEquals(Convention.WKT1,
-                "PROJCS[“Great_Britian_National_Grid”,\n" +
-                "  GEOGCS[“Airy1830”,\n" +
-                "    DATUM[“Airy1830”,\n" +
-                "      SPHEROID[“Airy1830”, 6377563.396, 299.3249753150345]],\n" +
-                "      PRIMEM[“Greenwich”, 0.0],\n" +
-                "    UNIT[“degree”, 0.017453292519943295],\n" +
-                "    AXIS[“Longitude”, EAST],\n" +
-                "    AXIS[“Latitude”, NORTH]],\n" +
-                "  PROJECTION[“Transverse_Mercator”, AUTHORITY[“EPSG”, “9807”]],\n" +
-                "  PARAMETER[“latitude_of_origin”, -2.0],\n" +
-                "  PARAMETER[“central_meridian”, 49.0],\n" +
-                "  PARAMETER[“scale_factor”, 1.0],\n" +
-                "  PARAMETER[“false_easting”, 400000.0],\n" +
-                "  PARAMETER[“false_northing”, -100000.0],\n" +
-                "  UNIT[“metre”, 1],\n" +
-                "  AXIS[“Easting”, EAST],\n" +
-                "  AXIS[“Northing”, NORTH]]", projectedCRS);
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
index 21b2172..24c44b8 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
@@ -87,7 +87,6 @@
  * @module
  */
 @DependsOn({
-    org.apache.sis.referencing.factory.GeodeticObjectFactoryTest.class,
     org.apache.sis.referencing.factory.AuthorityFactoryProxyTest.class,
     org.apache.sis.referencing.factory.IdentifiedObjectFinderTest.class
 })
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
index 7b69c8d..d48293f 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
@@ -115,8 +115,7 @@
      */
     private static InstallationScriptProvider getScripts() throws IOException {
         final InstallationScriptProvider scripts = new InstallationScriptProvider.Default(null);
-        assumeTrue("EPSG scripts not found in Databases/ExternalSources directory.",
-                scripts.getAuthorities().contains(Constants.EPSG));
+        assumeTrue(scripts.getAuthorities().contains(Constants.EPSG));
         return scripts;
     }
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
index de9c165..1cd81da 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
@@ -57,7 +57,7 @@
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
-import org.opengis.test.Assert;
+import org.apache.sis.test.Assert;
 import org.junit.BeforeClass;
 import org.junit.AfterClass;
 import org.junit.Test;
@@ -299,6 +299,7 @@
         if (targetCRS.getCoordinateSystem().getDimension() == 2) {
             target = TestUtilities.dropLastDimensions(target, 3, 2);
         }
+        tolerance = zTolerance; // Because GeoAPI 3.0 does not distinguish z axis from other axes (fixed in GeoAPI 3.1).
         verifyTransform(source, target);
         validate();
     }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
index 3fa306a..8301fa9 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationRegistryTest.java
@@ -18,10 +18,10 @@
 
 import java.util.List;
 import java.text.ParseException;
-import org.opengis.metadata.Identifier;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.SingleOperation;
@@ -103,7 +103,7 @@
      */
     public CoordinateOperationRegistryTest() throws FactoryException {
         final CRSAuthorityFactory crsFactory = CRS.getAuthorityFactory("EPSG");
-        assumeTrue("EPSG factory required.", crsFactory instanceof CoordinateOperationAuthorityFactory);
+        assumeTrue(crsFactory instanceof CoordinateOperationAuthorityFactory);
         registry = new CoordinateOperationRegistry((CoordinateOperationAuthorityFactory) crsFactory, factory, null);
     }
 
@@ -267,6 +267,7 @@
         zTolerance = Formulas.LINEAR_TOLERANCE;
         zDimension = new int[] {2};
         λDimension = new int[] {1};
+        tolerance  = zTolerance; // Because GeoAPI 3.0 does not distinguish z axis from other axes (fixed in GeoAPI 3.1).
         verifyTransform(new double[] {54.271680278,  0.098269657, 20.00},      // in grads east of Paris
                         new double[] {48.844443528,  2.424952028, 63.15});     // in degrees east of Greenwich
         validate();
@@ -302,6 +303,7 @@
         zTolerance = Formulas.LINEAR_TOLERANCE;
         zDimension = new int[] {2};
         λDimension = new int[] {1};
+        tolerance  = zTolerance; // Because GeoAPI 3.0 does not distinguish z axis from other axes (fixed in GeoAPI 3.1).
         verifyTransform(new double[] {0.088442691, 48.844512250, 20.00},      // in degrees east of Paris
                         new double[] {2.424952028, 48.844443528, 63.15});     // in degrees east of Greenwich
         validate();
@@ -357,7 +359,7 @@
     private static void assertEpsgNameWithoutIdentifierEqual(final String name, final IdentifiedObject object) {
         assertNotNull(name, object);
         assertEquals("name", name, object.getName().getCode());
-        for (final Identifier id : object.getIdentifiers()) {
+        for (final ReferenceIdentifier id : object.getIdentifiers()) {
             assertFalse("EPSG identifier not allowed for modified objects.", "EPSG".equalsIgnoreCase(id.getCodeSpace()));
         }
     }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
index d465be0..9b02949 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
@@ -21,6 +21,7 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.OperationMethod;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.util.ComparisonMode;
@@ -65,7 +66,7 @@
     {
         final Map<String,Object> properties = new HashMap<String,Object>(8);
         assertNull(properties.put(OperationMethod.NAME_KEY, method));
-        assertNull(properties.put(Identifier.CODESPACE_KEY, "EPSG"));
+        assertNull(properties.put(ReferenceIdentifier.CODESPACE_KEY, "EPSG"));
         assertNull(properties.put(Identifier.AUTHORITY_KEY, Citations.EPSG));
         /*
          * The parameter group for a Mercator projection is actually not empty, but it is not the purpose of
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultPassThroughOperationTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultPassThroughOperationTest.java
index 561f6cc..d55a88f 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultPassThroughOperationTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultPassThroughOperationTest.java
@@ -28,7 +28,7 @@
 import org.junit.Test;
 
 import static org.apache.sis.test.TestUtilities.getSingleton;
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
index 76b8348..76149bb 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
@@ -23,7 +23,7 @@
 import org.junit.Test;
 
 import static java.lang.Double.NaN;
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
index 54535d0..4cc34be 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
@@ -24,7 +24,6 @@
 import static java.lang.Double.NaN;
 
 // Test dependencies
-import org.opengis.test.ToleranceModifier;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestUtilities;
@@ -74,7 +73,6 @@
 
         final double delta = toRadians(100.0 / 60) / 1852;                  // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
-        toleranceModifier = ToleranceModifier.PROJECTION;
         tolerance = Formulas.LINEAR_TOLERANCE;
         final AlbersEqualArea kernel = (AlbersEqualArea) getKernel();
         assertTrue("isSpherical", isSpherical(kernel));
@@ -123,7 +121,6 @@
 
         final double delta = toRadians(100.0 / 60) / 1852;                  // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
-        toleranceModifier = ToleranceModifier.PROJECTION;
         tolerance = Formulas.LINEAR_TOLERANCE;
         final AlbersEqualArea kernel = (AlbersEqualArea) getKernel();
         assertFalse("isSpherical", isSpherical(kernel));
@@ -163,7 +160,6 @@
     @Test
     @DependsOnMethod("testEllipse")
     public void compareWithProj4() throws FactoryException, TransformException {
-        toleranceModifier = ToleranceModifier.PROJECTION;
         tolerance = Formulas.LINEAR_TOLERANCE;
 
         // Spherical case
@@ -215,7 +211,6 @@
                 0);         // False northing
 
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         verifyTransform(new double[] {0,        0,
                                       0,      +90,
                                       0,      -90},
@@ -246,7 +241,6 @@
                 200);       // False northing
 
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         derivativeDeltas = new double[] {100, 100};
         final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ConformalProjectionTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ConformalProjectionTest.java
index 98246fa..c9c0de2 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ConformalProjectionTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ConformalProjectionTest.java
@@ -202,20 +202,6 @@
                 return projection.dy_dφ(sinφ, cos(φ)) * expOfNorthing(projection, φ);
             }
         };
-        verifyInDomain(-89 * (PI/180), 89 * (PI/180));  // Verify from 85°S to 85°N.
-    }
-
-    /**
-     * Convenience method invoking {@link TransformTestCase#verifyInDomain} for an 1D transform.
-     */
-    private void verifyInDomain(final double min, final double max) throws TransformException {
-        derivativeDeltas = new double[] {2E-8};
-        isInverseTransformSupported = false;
-        verifyInDomain(
-                new double[] {min},     // Minimal value to test.
-                new double[] {max},     // Maximal value to test.
-                new int[]    {100},     // Number of points to test.
-                TestUtilities.createRandomNumberGenerator());
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/CylindricalEqualAreaTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/CylindricalEqualAreaTest.java
index 3e9267b..5597fed 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/CylindricalEqualAreaTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/CylindricalEqualAreaTest.java
@@ -18,7 +18,6 @@
 
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.TransformException;
-import org.opengis.test.ToleranceModifier;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.provider.LambertCylindricalEqualArea;
 import org.apache.sis.internal.referencing.provider.LambertCylindricalEqualAreaSpherical;
@@ -72,7 +71,6 @@
                 0,          // False easting
                 0);         // False northing
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         final double λ = 2;
         final double φ = 1;
         final double x = 222638.98;             // Test point from Proj.4.
@@ -102,7 +100,6 @@
                 0,          // False easting
                 0);         // False northing
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         final double λ = 2;
         final double φ = 1;
         final double x = 222390.10;             // Anti-regression values (not from an external source).
@@ -135,7 +132,6 @@
                 0,          // False easting
                 0);         // False northing
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         final double λ = 2;
         final double φ = 1;
         final double x = 222390.10;             // Anti-regression values (not from an external source).
@@ -166,7 +162,6 @@
                 200);       // False northing
 
         tolerance = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
         derivativeDeltas = new double[] {100, 100};
         final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
index 67e69a8..60c0063 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
@@ -39,6 +39,10 @@
 import static java.lang.Double.*;
 import static org.apache.sis.test.Assert.*;
 
+// Branch-specific imports
+import static org.junit.Assume.assumeTrue;
+import static org.apache.sis.test.Assert.PENDING_NEXT_GEOAPI_RELEASE;
+
 
 /**
  * Tests the {@link LambertConicConformal} class. We test using various values of the latitude of origin.
@@ -234,7 +238,7 @@
     @Test
     @DependsOnMethod("testLambertConicConformal2SP")
     public void testLambertConicConformalMichigan() throws FactoryException, TransformException {
-        createGeoApiTest(new LambertConformalMichigan()).testLambertConicConformalMichigan();
+        assumeTrue(PENDING_NEXT_GEOAPI_RELEASE);   // Test not available in GeoAPI 3.0
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
index 619a8e8..09d9616 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
@@ -20,7 +20,6 @@
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
-import org.opengis.test.referencing.ParameterizedTransformTest;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.referencing.provider.MapProjection;
@@ -72,8 +71,8 @@
      * @param  provider  the provider of the projection to test.
      * @return the GeoAPI test class using the given provider.
      */
-    static ParameterizedTransformTest createGeoApiTest(final MapProjection provider) {
-        return new ParameterizedTransformTest(new MathTransformFactoryMock(provider));
+    static ParameterizedTransformTestMock createGeoApiTest(final MapProjection provider) {
+        return new ParameterizedTransformTestMock(new MathTransformFactoryMock(provider));
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
index 0f15fe5..9639e35 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
@@ -22,10 +22,8 @@
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.provider.Mercator1SP;
 import org.apache.sis.internal.referencing.provider.Mercator2SP;
-import org.apache.sis.internal.referencing.provider.MercatorSpherical;
 import org.apache.sis.internal.referencing.provider.PseudoMercator;
 import org.apache.sis.internal.referencing.provider.MillerCylindrical;
-import org.apache.sis.internal.referencing.provider.RegionalMercator;
 import org.apache.sis.referencing.operation.transform.CoordinateDomain;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -36,6 +34,10 @@
 import static org.opengis.test.Assert.*;
 import static org.apache.sis.referencing.operation.projection.ConformalProjectionTest.LN_INFINITY;
 
+// Branch-specific imports
+import static org.junit.Assume.assumeTrue;
+import static org.apache.sis.test.Assert.PENDING_NEXT_GEOAPI_RELEASE;
+
 
 /**
  * Tests the {@link Mercator} projection.
@@ -215,7 +217,7 @@
     @Test
     @DependsOnMethod("testMercator2SP")
     public void testRegionalMercator() throws FactoryException, TransformException {
-        createGeoApiTest(new RegionalMercator()).testMercatorVariantC();
+        assumeTrue(PENDING_NEXT_GEOAPI_RELEASE);   // Test not available in GeoAPI 3.0
     }
 
     /**
@@ -230,7 +232,7 @@
     @Test
     @DependsOnMethod("testMercator1SP")
     public void testMercatorSpherical() throws FactoryException, TransformException {
-        createGeoApiTest(new MercatorSpherical()).testMercatorSpherical();
+        assumeTrue(PENDING_NEXT_GEOAPI_RELEASE);   // Test not available in GeoAPI 3.0
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
index cdd389d..e09b210 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
-import org.opengis.test.referencing.TransformTestCase;
+import org.apache.sis.referencing.operation.transform.TransformTestCase;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
@@ -24,9 +24,6 @@
 import static org.apache.sis.internal.metadata.ReferencingServices.NAUTICAL_MILE;
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import static org.apache.sis.internal.jdk8.JDK8.nextDown;
-
 
 /**
  * Tests the {@link NormalizedProjection} class.
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
index 1d7a5f5..26130dd 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
@@ -25,7 +25,6 @@
 import org.opengis.util.FactoryException;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
-import org.apache.sis.referencing.operation.matrix.Matrix2;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.test.DependsOnMethod;
@@ -33,7 +32,7 @@
 import org.junit.Test;
 
 import static java.lang.StrictMath.*;
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
@@ -211,21 +210,6 @@
     }
 
     /**
-     * Tests the <cite>Oblique Stereographic</cite> case (EPSG:9809).
-     * This test is defined in GeoAPI conformance test suite.
-     *
-     * @throws FactoryException if an error occurred while creating the map projection.
-     * @throws TransformException if an error occurred while projecting a coordinate.
-     *
-     * @see org.opengis.test.referencing.ParameterizedTransformTest#testObliqueStereographic()
-     */
-    @Test
-    @DependsOnMethod({"testTransform", "testInverseTransform"})
-    public void testObliqueStereographic() throws FactoryException, TransformException {
-        createGeoApiTest(new org.apache.sis.internal.referencing.provider.ObliqueStereographic()).testObliqueStereographic();
-    }
-
-    /**
      * Verifies the consistency of spherical formulas with the elliptical formulas.
      * This test transforms the point given in the EPSG guide and takes the result
      * of the elliptical implementation as a reference.
@@ -337,9 +321,7 @@
         final Matrix derivative = spherical.transform(srcPts, 0, null, 0, true);
 
         tolerance = 1E-12;
-        assertMatrixEquals("Spherical derivative", reference, derivative,
-                new Matrix2(tolerance, tolerance,
-                            tolerance, tolerance));
+        assertMatrixEquals("Spherical derivative", reference, derivative, tolerance);
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ParameterizedTransformTestMock.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ParameterizedTransformTestMock.java
new file mode 100644
index 0000000..1588401
--- /dev/null
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ParameterizedTransformTestMock.java
@@ -0,0 +1,80 @@
+/*
+ * 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.referencing.operation.projection;
+
+import org.opengis.referencing.operation.MathTransformFactory;
+
+import static org.junit.Assume.*;
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Placeholder for a GeoAPI 3.1 method which was not available in GeoAPI 3.0.
+ * This placeholder does nothing. See Apache SIS JDK6 branch for a real test.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.6
+ * @module
+ */
+final class ParameterizedTransformTestMock {
+    ParameterizedTransformTestMock(MathTransformFactory factory) {
+        // See GeoAPI 3.1 for real construction.
+    }
+
+    public void testMercator1SP() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testMercator2SP() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testPseudoMercator() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testMiller() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testLambertConicConformal1SP() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testLambertConicConformal2SP() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    public void testLambertConicConformalBelgium() {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java
index d415658..eef8392 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java
@@ -128,7 +128,7 @@
      */
     @Test
     public void testPolarStereographicA() throws FactoryException, TransformException {
-        createGeoApiTest(new PolarStereographicA()).testPolarStereographicA();
+        new PolarStereographicA();  // Test creation only, as GeoAPI 3.0 did not yet had the test method.
     }
 
     /**
@@ -142,7 +142,7 @@
      */
     @Test
     public void testPolarStereographicB() throws FactoryException, TransformException {
-        createGeoApiTest(new PolarStereographicB()).testPolarStereographicB();
+        new PolarStereographicB();  // Test creation only, as GeoAPI 3.0 did not yet had the test method.
     }
 
     /**
@@ -156,7 +156,7 @@
      */
     @Test
     public void testPolarStereographicC() throws FactoryException, TransformException {
-        createGeoApiTest(new PolarStereographicC()).testPolarStereographicC();
+        new PolarStereographicC();  // Test creation only, as GeoAPI 3.0 did not yet had the test method.
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java
index 5952a8a..4e6e27c 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java
@@ -68,7 +68,7 @@
      */
     @Test
     public void testTransverseMercator() throws FactoryException, TransformException {
-        createGeoApiTest(new org.apache.sis.internal.referencing.provider.TransverseMercator()).testTransverseMercator();
+        new org.apache.sis.internal.referencing.provider.TransverseMercator();  // Test creation only, as GeoAPI 3.0 did not yet had the test method.
     }
 
     /**
@@ -83,7 +83,7 @@
     @Test
     @DependsOnMethod("testTransverseMercator")
     public void testTransverseMercatorSouthOrientated() throws FactoryException, TransformException {
-        createGeoApiTest(new TransverseMercatorSouth()).testTransverseMercatorSouthOrientated();
+        new TransverseMercatorSouth();  // Test creation only, as GeoAPI 3.0 did not yet had the test method.
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java
index 246f48c..f49da57 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToPolarTest.java
@@ -20,7 +20,6 @@
 import org.opengis.referencing.operation.TransformException;
 
 // Test dependencies
-import org.opengis.test.referencing.TransformTestCase;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestUtilities;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java
index 6941a97..9c9ace4 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CartesianToSphericalTest.java
@@ -20,7 +20,6 @@
 import org.opengis.referencing.operation.TransformException;
 
 // Test dependencies
-import org.opengis.test.referencing.TransformTestCase;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestUtilities;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java
index 76ff618..c66c04d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ContextualParametersTest.java
@@ -33,7 +33,7 @@
 
 import static java.lang.StrictMath.PI;
 import static java.lang.StrictMath.toRadians;
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
index 1fbab30..68079bb 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
@@ -48,7 +48,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
index de642d5..950d02c 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
@@ -33,7 +33,6 @@
 import static java.lang.StrictMath.toRadians;
 
 // Test dependencies
-import org.opengis.test.ToleranceModifier;
 import org.apache.sis.internal.referencing.provider.GeocentricTranslationTest;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -116,6 +115,7 @@
         tolerance  = GeocentricTranslationTest.precision(1);        // Required precision for (λ,φ)
         zTolerance = Formulas.LINEAR_TOLERANCE / 2;                 // Required precision for h
         zDimension = new int[] {2};                                 // Dimension of h where to apply zTolerance
+        tolerance  = 1E-4;                                          // Other SIS branches use a stricter threshold.
         verifyTransform(GeocentricTranslationTest.samplePoint(2),   // X = 3771793.968,  Y = 140253.342,  Z = 5124304.349 metres
                         GeocentricTranslationTest.samplePoint(1));  // 53°48'33.820"N, 02°07'46.380"E, 73.00 metres
     }
@@ -135,7 +135,7 @@
         final double delta = toRadians(100.0 / 60) / 1852;          // Approximatively 100 metres
         derivativeDeltas  = new double[] {delta, delta, 100};       // (Δλ, Δφ, Δh)
         tolerance         = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
+//      toleranceModifier = ToleranceModifier.PROJECTION;
         createGeodeticConversion(CommonCRS.WGS84.ellipsoid(), true);
         verifyInDomain(CoordinateDomain.GEOGRAPHIC, 306954540);
     }
@@ -157,7 +157,7 @@
         final double delta = toRadians(100.0 / 60) / 1852;
         derivativeDeltas  = new double[] {delta, delta, 100};
         tolerance         = Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifier.PROJECTION;
+//      toleranceModifier = ToleranceModifier.PROJECTION;
         verifyInverse(new double[] {40, 30, 10000});
     }
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1DTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1DTest.java
index 6a7877b..74bb388 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1DTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ExponentialTransform1DTest.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.referencing.operation.transform;
 
-import java.util.EnumSet;
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.TransformException;
 import static java.lang.StrictMath.*;
@@ -27,11 +26,6 @@
 import org.apache.sis.test.DependsOnMethod;
 import static org.apache.sis.test.ReferencingAssert.*;
 
-// Branch-dependent imports
-import org.opengis.test.CalculationType;
-import org.opengis.test.ToleranceModifier;
-import org.opengis.test.ToleranceModifiers;
-
 
 /**
  * Tests the {@link ExponentialTransform1D} class. Note that this is closely related to
@@ -66,9 +60,8 @@
      * Creates a new test case.
      */
     public ExponentialTransform1DTest() {
-        tolerance         = 1E-14;
-        toleranceModifier = ToleranceModifier.RELATIVE;
-        derivativeDeltas  = new double[] {0.001};
+        tolerance         = 1E-5; // Tolerance is much smaller on other branches.
+//      toleranceModifier = ToleranceModifier.RELATIVE; // Not available on GeoAPI 3.0.
     }
 
     /**
@@ -104,7 +97,6 @@
             expected[i] = value;
         }
         verifyTransform(values, expected);
-        verifyDerivative(2.5); // Test at a hard-coded point.
     }
 
     /**
@@ -138,13 +130,6 @@
     private void testAffinePostConcatenation(final double base) throws TransformException {
         transform = MathTransforms.concatenate(ExponentialTransform1D.create(base, SCALE),
                 LinearTransform1D.create(C1, C0));
-        /*
-         * The inverse transforms in this test case have high rounding errors.
-         * Those errors are low for values close to zero, and increase fast for higher values.
-         * We scale the default tolerance (1E-14) by 1E+8, which give us a tolerance of 1E-6.
-         */
-        toleranceModifier = ToleranceModifiers.concatenate(toleranceModifier,
-                ToleranceModifiers.scale(EnumSet.of(CalculationType.INVERSE_TRANSFORM), 1E+8));
         run(ConcatenatedTransformDirect1D.class, base, SCALE, false, true);
     }
 
@@ -154,10 +139,6 @@
     private void testAffineConcatenations(final double base) throws TransformException {
         final LinearTransform1D linear = LinearTransform1D.create(C1, C0);
         transform = MathTransforms.concatenate(linear, ExponentialTransform1D.create(base, SCALE), linear);
-
-        // See testAffinePostConcatenation for an explanation about why we relax tolerance.
-        toleranceModifier = ToleranceModifiers.concatenate(toleranceModifier,
-                ToleranceModifiers.scale(EnumSet.of(CalculationType.INVERSE_TRANSFORM), 1E+8));
         run(ConcatenatedTransformDirect1D.class, base, SCALE, true, true);
     }
 
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
index a054656..cfc4df1 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1DTest.java
@@ -20,7 +20,6 @@
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.referencing.operation.TransformException;
-import org.opengis.test.referencing.TransformTestCase;
 import org.junit.Test;
 
 import static org.opengis.test.Assert.*;
@@ -35,7 +34,7 @@
  * @version 0.7
  * @module
  */
-public final strictfp class LinearInterpolator1DTest extends TransformTestCase {
+public final strictfp class LinearInterpolator1DTest extends MathTransformTestCase {
     /**
      * The values of the <i>y=f(x)</i> function to test.
      */
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearTransformTest.java
index 05ae03f..2367e9d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LinearTransformTest.java
@@ -28,6 +28,9 @@
 import org.apache.sis.test.TestRunner;
 import static org.opengis.test.Assert.*;
 
+// Branch-dependent imports
+import org.junit.Ignore;
+
 
 /**
  * Tests various implementation of the {@link LinearTransform} interface by inheriting the tests defined
@@ -69,6 +72,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testIdentity1D() throws FactoryException, TransformException {
         super.testIdentity1D();
         assertInstanceOf("Unexpected implementation.", IdentityTransform1D.class, transform);
@@ -82,6 +86,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testIdentity2D() throws FactoryException, TransformException {
         super.testIdentity2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -95,6 +100,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testIdentity3D() throws FactoryException, TransformException {
         super.testIdentity3D();
         assertInstanceOf("Unexpected implementation.", IdentityTransform.class, transform);
@@ -108,6 +114,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testAxisSwapping2D() throws FactoryException, TransformException {
         super.testAxisSwapping2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -121,6 +128,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testSouthOrientated2D() throws FactoryException, TransformException {
         super.testSouthOrientated2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -134,6 +142,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testTranslatation2D() throws FactoryException, TransformException {
         super.testTranslatation2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -147,6 +156,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testUniformScale2D() throws FactoryException, TransformException {
         super.testUniformScale2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -160,6 +170,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testGenericScale2D() throws FactoryException, TransformException {
         super.testGenericScale2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -173,6 +184,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testRotation2D() throws FactoryException, TransformException {
         super.testRotation2D();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -186,6 +198,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testGeneral() throws FactoryException, TransformException {
         super.testGeneral();
         assertInstanceOf("Unexpected implementation.", AffineTransform2D.class, transform);
@@ -199,6 +212,7 @@
      */
     @Test
     @Override
+    @Ignore(MESSAGE)
     public void testDimensionReduction() throws FactoryException, TransformException {
         super.testDimensionReduction();
         assertInstanceOf("Unexpected implementation.", ProjectiveTransform.class, transform);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1DTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1DTest.java
index 6fd722d..4bd7750 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1DTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/LogarithmicTransform1DTest.java
@@ -26,9 +26,6 @@
 import org.apache.sis.test.DependsOnMethod;
 import static org.apache.sis.test.ReferencingAssert.*;
 
-// Branch-dependent imports
-import org.opengis.test.ToleranceModifier;
-
 
 /**
  * Tests the {@link LogarithmicTransform1D} class. Note that this is closely related to
@@ -55,9 +52,8 @@
      * Creates a new test case.
      */
     public LogarithmicTransform1DTest() {
-        tolerance         = 2E-14;
-        toleranceModifier = ToleranceModifier.RELATIVE;
-        derivativeDeltas  = new double[] {0.001};
+        tolerance         = 1E-5; // Tolerance is much smaller on other branches.
+//      toleranceModifier = ToleranceModifier.RELATIVE; // Not available on GeoAPI 3.0.
     }
 
     /**
@@ -95,7 +91,6 @@
             expected[i] = value;
         }
         verifyTransform(values, expected);
-        verifyDerivative(2.5); // Test at a hard-coded point.
     }
 
     /**
@@ -224,6 +219,5 @@
             expected[i] = ExponentialTransform1DTest.SCALE * pow(10, log(value) / lnBase + C0);
         }
         verifyTransform(values, expected);
-        verifyDerivative(2.5); // Test at a hard-coded point.
     }
 }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
index c2023fea..bcff6a2 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
@@ -18,17 +18,14 @@
 
 import java.util.Random;
 import java.io.IOException;
-import org.opengis.util.Factory;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.MathTransform2D;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.geometry.DirectPosition;
 import org.opengis.metadata.Identifier;
 import org.apache.sis.parameter.Parameterized;
-import org.apache.sis.measure.Longitude;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.io.TableAppender;
@@ -39,15 +36,10 @@
 
 // Test imports
 import org.opengis.test.Validators;
-import org.opengis.test.referencing.TransformTestCase;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.ReferencingAssert;
 import static org.opengis.test.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.test.CalculationType;
-import org.opengis.test.ToleranceModifier;
-
 
 /**
  * Base class for tests of {@link AbstractMathTransform} implementations.
@@ -113,66 +105,6 @@
      * Creates a new test case.
      */
     protected MathTransformTestCase() {
-        this(new Factory[0]);
-    }
-
-    /**
-     * Creates a new test case which will use the given factories. Those factories will be given to
-     * {@link org.opengis.test.ImplementationDetails#configuration(Factory[])} in order to decide
-     * which tests should be enabled.
-     *
-     * @param factories The factories to be used by the test.
-     */
-    protected MathTransformTestCase(final Factory... factories) {
-        super(factories);
-        /*
-         * Use 'zTolerance' threshold instead of 'tolerance' when comparing vertical coordinate values.
-         */
-        toleranceModifier = new ToleranceModifier() {
-            @Override
-            public void adjust(final double[] tolerance, final DirectPosition coordinate, final CalculationType mode) {
-                if (mode != CalculationType.IDENTITY) {
-                    final int i = forComparison(zDimension, mode);
-                    if (i >= 0 && i < tolerance.length) {
-                        tolerance[i] = zTolerance;
-                    }
-                }
-            }
-        };
-    }
-
-    /**
-     * Returns the value to use from the {@link #λDimension} or {@link zDimension} for the
-     * given comparison mode, or -1 if none.
-     */
-    @SuppressWarnings("fallthrough")
-    private static int forComparison(final int[] config, final CalculationType mode) {
-        if (config != null) {
-            switch (mode) {
-                case INVERSE_TRANSFORM: if (config.length >= 2) return config[1];       // Intentional fallthrough.
-                case DIRECT_TRANSFORM:  if (config.length >= 1) return config[0];
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Invoked by all {@code assertCoordinateEquals(…)} methods before two positions are compared.
-     * The SIS implementation ensures that longitude values are contained in the ±180° range,
-     * applying 360° shifts if needed.
-     *
-     * @param expected The expected ordinate value provided by the test case.
-     * @param actual   The ordinate value computed by the {@linkplain #transform transform} being tested.
-     * @param mode     Indicates if the coordinates being compared are the result of a direct
-     *                 or inverse transform, or if strict equality is requested.
-     */
-    @Override
-    protected final void normalize(final DirectPosition expected, final DirectPosition actual, final CalculationType mode) {
-        final int i = forComparison(λDimension, mode);
-        if (i >= 0) {
-            expected.setOrdinate(i, Longitude.normalize(expected.getOrdinate(i)));
-            actual  .setOrdinate(i, Longitude.normalize(actual  .getOrdinate(i)));
-        }
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
index 630ea9c..ea76ba1 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformsTest.java
@@ -25,7 +25,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
index 8b5e437..84cd22a 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
@@ -16,38 +16,23 @@
  */
 package org.apache.sis.referencing.operation.transform;
 
-import java.util.Arrays;
-import java.io.IOException;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.datum.Ellipsoid;
-import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.parameter.ParameterValueGroup;
-import org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolation;
-import org.apache.sis.internal.referencing.provider.AbridgedMolodensky;
 import org.apache.sis.internal.referencing.provider.Molodensky;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.math.StatisticsFormat;
-import org.apache.sis.math.Statistics;
 
 import static java.lang.StrictMath.*;
-import static org.apache.sis.internal.metadata.ReferencingServices.NAUTICAL_MILE;
 
 // Test dependencies
-import org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolationTest;
 import org.apache.sis.internal.referencing.provider.GeocentricTranslationTest;
-import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestUtilities;
-import org.apache.sis.test.TestCase;
-import org.opengis.test.CalculationType;
-import org.opengis.test.ToleranceModifier;
-import org.opengis.test.ToleranceModifiers;
-import org.opengis.test.referencing.ParameterizedTransformTest;
 import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
@@ -85,65 +70,6 @@
     }
 
     /**
-     * Compares the Molodensky (non-abridged) transform with a geocentric translation.
-     * Molodensky is an approximation of geocentric translation, so we test here how good this approximation is.
-     * If {@link TestCase#verbose} is {@code true}, then this method will print error statistics.
-     *
-     * @throws FactoryException if an error occurred while creating a transform step.
-     * @throws TransformException if a transformation failed.
-     * @throws IOException should never happen.
-     *
-     * @see #compareWithGeocentricTranslation()
-     */
-    @SuppressWarnings("fallthrough")
-    private void compareWithGeocentricTranslation(
-            final Ellipsoid source, final Ellipsoid target,
-            final double tX,   final double tY,   final double tZ,
-            final double xmin, final double ymin, final double zmin,
-            final double xmax, final double ymax, final double zmax)
-            throws FactoryException, TransformException, IOException
-    {
-        final MathTransform reference;
-        final MathTransformFactory factory = DefaultFactories.forBuildin(MathTransformFactory.class);
-        transform = MolodenskyTransform.createGeodeticTransformation(factory, source, true, target, true, tX, tY, tZ, false);
-        reference = GeocentricTranslationTest.createDatumShiftForGeographic3D(factory, source, target, tX, tY, tZ);
-        final float[] srcPts = verifyInDomain(
-                new double[] {xmin, ymin, zmin},
-                new double[] {xmax, ymax, zmax},
-                new int[]    {  10,   10,   10},
-                TestUtilities.createRandomNumberGenerator(103627524044558476L));
-        /*
-         * Transform the same input coordinates using Molodensky transform (actual) and using the reference
-         * implementation (expected). If we were asked to print statistics, compute them before to test the
-         * values since the statistics may be a useful information in case of problem.
-         */
-        final double[] actual   = new double[srcPts.length];
-        final double[] expected = new double[srcPts.length];
-        transform.transform(srcPts, 0, actual,   0, srcPts.length / 3);
-        reference.transform(srcPts, 0, expected, 0, srcPts.length / 3);
-        if (TestCase.VERBOSE) {
-            final Statistics[] stats = {
-                new Statistics("|Δλ| (~cm)"),
-                new Statistics("|Δφ| (~cm)"),
-                new Statistics("|Δh| (cm)")
-            };
-            for (int i=0; i<srcPts.length; i++) {
-                double Δ = actual[i] - expected[i];
-                final int j = i % stats.length;
-                switch (j) {
-                    case 0: Δ *= cos(toRadians(expected[i+1]));     // Fall through
-                    case 1: Δ *= 60 * NAUTICAL_MILE; break;         // Approximative conversion to metres
-                }
-                Δ *= 100;   // Conversion to centimetres.
-                stats[j].accept(abs(Δ));
-            }
-            StatisticsFormat.getInstance().format(stats, TestCase.out);
-        }
-        assertCoordinatesEqual("Comparison of Molodensky and geocentric translation", 3,
-                expected, 0, actual, 0, expected.length / 3, CalculationType.DIRECT_TRANSFORM);
-    }
-
-    /**
      * Creates a Molodensky transform for a datum shift from WGS84 to ED50.
      * Tolerance thresholds are also initialized.
      *
@@ -214,6 +140,7 @@
         final double[] sample   = GeocentricTranslationTest.samplePoint(1);
         final double[] expected = GeocentricTranslationTest.samplePoint(5);
         isInverseTransformSupported = false;
+        tolerance = Formulas.LINEAR_TOLERANCE;  // Other SIS branches use a stricter threshold.
         verifyTransform(sample, expected);
         /*
          * When testing the inverse transformation, we need to relax slightly
@@ -243,6 +170,7 @@
         final double[] sample   = GeocentricTranslationTest.samplePoint(1);
         final double[] expected = GeocentricTranslationTest.samplePoint(4);
         isInverseTransformSupported = false;
+        tolerance = Formulas.LINEAR_TOLERANCE;  // Other SIS branches use a stricter threshold.
         verifyTransform(sample, expected);
         /*
          * When testing the inverse transformation, we need to relax slightly
@@ -254,81 +182,6 @@
     }
 
     /**
-     * Tests the point used in {@link FranceGeocentricInterpolationTest}. We use this test for measuring the
-     * errors induced by the use of the Molodensky approximation instead than a real geocentric translation.
-     * The error is approximatively 1 centimetre, which is about 6 times more than the accuracy of the point
-     * given in {@code FranceGeocentricInterpolationTest}.
-     *
-     * @throws FactoryException if an error occurred while creating the transform.
-     * @throws TransformException if transformation of a point failed.
-     *
-     * @see GeocentricTranslationTest#testFranceGeocentricInterpolationPoint()
-     */
-    @Test
-    @DependsOnMethod("testMolodensky")
-    public void testFranceGeocentricInterpolationPoint() throws FactoryException, TransformException {
-        transform = MolodenskyTransform.createGeodeticTransformation(
-                DefaultFactories.forBuildin(MathTransformFactory.class),
-                HardCodedDatum.NTF.getEllipsoid(), true,        // Clarke 1880 (IGN)
-                CommonCRS.ETRS89.ellipsoid(), true,             // GRS 1980 ellipsoid
-               -FranceGeocentricInterpolation.TX,
-               -FranceGeocentricInterpolation.TY,
-               -FranceGeocentricInterpolation.TZ,
-                false);
-        /*
-         * Code below is a copy-and-paste of GeocentricTranslationTest.testFranceGeocentricInterpolationPoint(),
-         * but with the tolerance threshold increased. We do not let the error goes beyond 1 cm however.
-         */
-        tolerance = min(Formulas.ANGULAR_TOLERANCE, FranceGeocentricInterpolationTest.ANGULAR_TOLERANCE * 6);
-        final double[] source   = Arrays.copyOf(FranceGeocentricInterpolationTest.samplePoint(1), 3);
-        final double[] expected = Arrays.copyOf(FranceGeocentricInterpolationTest.samplePoint(2), 3);
-        expected[2] = 43.15;  // Anti-regression (this value is not provided in NTG_88 guidance note).
-        verifyTransform(source, expected);
-        validate();
-    }
-
-    /**
-     * Compares the Molodensky (non-abridged) transforms with geocentric translations.
-     * Molodensky is an approximation of geocentric translation, so we test here how good this
-     * approximation is. This test performs the comparison for the following transformations:
-     *
-     * <ul>
-     *   <li>Transformation from NTF to RGF93. Those CRS are the source and target of <cite>"France geocentric
-     *       interpolation"</cite> (ESPG:9655). This test allows us to verify the accuracy documented in
-     *       {@link InterpolatedGeocentricTransform}.</li>
-     *   <li>(More areas may be added later).</li>
-     * </ul>
-     *
-     * If {@link TestCase#verbose} is {@code true}, then this method will print error statistics.
-     *
-     * @throws FactoryException if an error occurred while creating a transform step.
-     * @throws TransformException if a transformation failed.
-     * @throws IOException should never happen.
-     *
-     * @see #testFranceGeocentricInterpolationPoint()
-     */
-    @Test
-    @DependsOnMethod("testFranceGeocentricInterpolationPoint")
-    public void compareWithGeocentricTranslation() throws FactoryException, TransformException, IOException {
-        /*
-         * Disable the test for inverse transformations because they are not the purpose of this test.
-         * Errors of inverse transformations are added to the error of forward transformations, which
-         * would force us to double the tolerance threshold.
-         */
-        isInverseTransformSupported = false;
-        tolerance         = 3*Formulas.LINEAR_TOLERANCE; // To be converted in degrees by ToleranceModifier.GEOGRAPHIC
-        zTolerance        = 4*Formulas.LINEAR_TOLERANCE;
-        toleranceModifier = ToleranceModifiers.concatenate(ToleranceModifier.GEOGRAPHIC, toleranceModifier);
-        compareWithGeocentricTranslation(HardCodedDatum.NTF.getEllipsoid(),   // Clarke 1880 (IGN)
-                                         CommonCRS.ETRS89.ellipsoid(),        // GRS 1980 ellipsoid
-                                         FranceGeocentricInterpolation.TX,
-                                         FranceGeocentricInterpolation.TY,
-                                         FranceGeocentricInterpolation.TZ,
-                                         -5.5, 41.0, -200,   // Geographic area of GR2DF97A datum shift grid.
-                                         10.0, 52.0, +200);
-    }
-
-    /**
      * Tests conversion of random points. The test is performed with the Molodensky transform,
      * not the abridged one, because the errors caused by the abridged Molodensky method are
      * too high for this test.
@@ -342,7 +195,7 @@
         create(false);
         tolerance  = Formulas.LINEAR_TOLERANCE * 3;     // To be converted in degrees by ToleranceModifier.GEOGRAPHIC
         zTolerance = Formulas.LINEAR_TOLERANCE * 2;
-        toleranceModifier = ToleranceModifiers.concatenate(ToleranceModifier.GEOGRAPHIC, toleranceModifier);
+//      toleranceModifier = ToleranceModifiers.concatenate(ToleranceModifier.GEOGRAPHIC, toleranceModifier);
         verifyInDomain(new double[] {-179, -85, -500},
                        new double[] {+179, +85, +500},
                        new int[]    {   8,   8,    8},
@@ -377,18 +230,6 @@
     }
 
     /**
-     * Runs the test defined in the GeoAPI-conformance module.
-     *
-     * @throws FactoryException if an error occurred while creating a transform step.
-     * @throws TransformException if a transformation failed.
-     */
-    @Test
-    @DependsOnMethod("testProvider")
-    public void runGeoapiTest() throws FactoryException, TransformException {
-        new ParameterizedTransformTest(new MathTransformFactoryMock(new AbridgedMolodensky())).testAbridgedMolodensky();
-    }
-
-    /**
      * Verifies that creating a Molodensky operation with same source and target ellipsoid and zero translation
      * results in an identity affine transform.
      *
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
index 262c308..acc7e0e 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PassThroughTransformTest.java
@@ -32,8 +32,7 @@
 import static org.junit.Assert.*;
 
 // Branch-dependent imports
-import org.opengis.test.CalculationType;
-import org.opengis.test.ToleranceModifier;
+// (all imports removed)
 
 
 /**
@@ -192,36 +191,24 @@
         /*
          * Now process to the transform and compares the results with the expected ones.
          */
-        tolerance         = 0; // Results should be strictly identical because we used the same inputs.
-        toleranceModifier = null;
+        tolerance = 0; // Results should be strictly identical because we used the same inputs.
         final double[] transformedData = new double[expectedData.length];
         transform.transform(passthroughData, 0, transformedData, 0, numPts);
         assertCoordinatesEqual("Direct transform.", passthroughDim,
-                expectedData, 0, transformedData, 0, numPts, CalculationType.DIRECT_TRANSFORM);
+                expectedData, 0, transformedData, 0, numPts, false);
         /*
          * Test inverse transform.
          */
-        tolerance         = 1E-8;
-        toleranceModifier = ToleranceModifier.RELATIVE;
+        tolerance = 1E-8;
         Arrays.fill(transformedData, Double.NaN);
         transform.inverse().transform(expectedData, 0, transformedData, 0, numPts);
         assertCoordinatesEqual("Inverse transform.", passthroughDim,
-                passthroughData, 0, transformedData, 0, numPts, CalculationType.INVERSE_TRANSFORM);
+                passthroughData, 0, transformedData, 0, numPts, false);
         /*
          * Verify the consistency between different 'transform(…)' methods.
          */
         final float[] sourceAsFloat = Numerics.copyAsFloats(passthroughData);
         final float[] targetAsFloat = verifyConsistency(sourceAsFloat);
         assertEquals("Unexpected length of transformed array.", expectedData.length, targetAsFloat.length);
-        /*
-         * We use a relatively high tolerance threshold because result are
-         * computed using inputs stored as float values.
-         */
-        if (transform instanceof LinearTransform) {
-            tolerance         = 1E-4;
-            toleranceModifier = ToleranceModifier.RELATIVE;
-            assertCoordinatesEqual("A transformed value is wrong.", passthroughDim,
-                    expectedData, 0, targetAsFloat, 0, numPts, CalculationType.DIRECT_TRANSFORM);
-        }
     }
 }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java
index a043f11..16a2b6b 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PolarToCartesianTest.java
@@ -24,7 +24,6 @@
 import static java.lang.StrictMath.*;
 
 // Test dependencies
-import org.opengis.test.referencing.TransformTestCase;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestUtilities;
 import org.junit.Test;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java
index fd4c200..a9ae24f 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java
@@ -21,7 +21,6 @@
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.MathTransform2D;
 import org.opengis.referencing.operation.MathTransformFactory;
-import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.internal.referencing.provider.Affine;
@@ -33,11 +32,14 @@
 import org.apache.sis.test.DependsOn;
 import org.junit.runner.RunWith;
 import org.junit.After;
-import org.junit.Test;
 import static org.opengis.test.Assert.*;
 
 // Branch-dependent imports
-import org.opengis.test.referencing.AffineTransformTest;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.test.referencing.TransformTestCase;
 
 
 /**
@@ -53,19 +55,29 @@
  */
 @RunWith(TestRunner.class)
 @DependsOn({AbstractMathTransformTest.class, ScaleTransformTest.class})
-public strictfp class ProjectiveTransformTest extends AffineTransformTest {
+public strictfp class ProjectiveTransformTest extends TransformTestCase {
+    /**
+     * The factory to use for creating linear transforms.
+     */
+    private final MathTransformFactory mtFactory;
+
+    /**
+     * The matrix for the tested transform.
+     */
+    private Matrix matrix;
+
     /**
      * For {@link LinearTransformTest} constructor only.
      */
     ProjectiveTransformTest(final MathTransformFactory factory) {
-        super(factory);
+        mtFactory = factory;
     }
 
     /**
      * Creates a new test suite.
      */
     public ProjectiveTransformTest() {
-        super(new MathTransformFactoryBase() {
+        this(new MathTransformFactoryBase() {
             @Override
             public MathTransform createAffineTransform(final Matrix matrix) {
                 final ProjectiveTransform pt;
@@ -88,7 +100,10 @@
     }
 
     /*
-     * Inherit all the tests from GeoAPI:
+     * GeoAPI 3.1 defines the following tests. However since those tests are not available
+     * in GeoAPI 3.0, we put empty placeholder. For running the real test, see for example
+     * the JDK6 branch of Apache SIS.
+     *
      *    - testIdentity1D()
      *    - testIdentity2D()
      *    - testIdentity3D()
@@ -102,6 +117,64 @@
      *    - testDimensionReduction()
      */
 
+    static final String MESSAGE = "This test is not available in GeoAPI 3.0. "
+            + "See Apache SIS JDK6, JDK7 or JDK8 branch for the actual tests.";
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testIdentity1D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testIdentity2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testIdentity3D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testAxisSwapping2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testSouthOrientated2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testTranslatation2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testUniformScale2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testGenericScale2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testRotation2D() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testGeneral() throws FactoryException, TransformException {
+    }
+
+    @Test
+    @Ignore(MESSAGE)
+    public void testDimensionReduction() throws FactoryException, TransformException {
+    }
+
     /**
      * Tests {@link ProjectiveTransform#optimize()}. In particular this method verifies that a non-square matrix
      * that looks like diagonal is not confused with a real diagonal matrix.
@@ -121,14 +194,14 @@
         });
         transform = new ProjectiveTransform(matrix).optimize();
         assertInstanceOf("Non-diagonal matrix shall not be handled by ScaleTransform.", ProjectiveTransform.class, transform);
-        verifyConsistency(1, 2, 3,   -3, -2, -1);
+        verifyConsistency(new float[] {1, 2, 3,   -3, -2, -1});
         /*
          * Remove the "problematic" row. The new transform should now be optimizable.
          */
         matrix = ((MatrixSIS) matrix).removeRows(3, 4);
         transform = new ProjectiveTransform(matrix).optimize();
         assertInstanceOf("Diagonal matrix should be handled by a specialized class.", ScaleTransform.class, transform);
-        verifyConsistency(1, 2, 3,   -3, -2, -1);
+        verifyConsistency(new float[] {1, 2, 3,   -3, -2, -1});
     }
 
     /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ScaleTransformTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ScaleTransformTest.java
index 4bb4b8e..eb3b4ef 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ScaleTransformTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ScaleTransformTest.java
@@ -25,7 +25,7 @@
 
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
-import org.opengis.test.Assert;
+import org.apache.sis.test.Assert;
 import org.junit.Test;
 
 import static org.opengis.test.Assert.*;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java
index 33e2f55..f539521 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SphericalToCartesianTest.java
@@ -24,7 +24,6 @@
 import static java.lang.StrictMath.*;
 
 // Test dependencies
-import org.opengis.test.referencing.TransformTestCase;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestUtilities;
 import org.junit.Test;
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransferFunctionTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransferFunctionTest.java
index bcf91da..00852b3 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransferFunctionTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransferFunctionTest.java
@@ -24,7 +24,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
index fe003e8..13c6645 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
@@ -24,7 +24,7 @@
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
index c8a86a5..41df35d 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java
@@ -30,7 +30,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformTestCase.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformTestCase.java
new file mode 100644
index 0000000..1a9ba7e
--- /dev/null
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformTestCase.java
@@ -0,0 +1,68 @@
+/*
+ * 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.referencing.operation.transform;
+
+import java.util.Random;
+
+import static org.junit.Assume.*;
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Placeholder for a GeoAPI 3.1 method which was not available in GeoAPI 3.0.
+ * This placeholder does nothing. See Apache SIS JDK6 branch for a real test.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.6
+ * @module
+ */
+public class TransformTestCase extends org.opengis.test.referencing.TransformTestCase {
+    /**
+     * The deltas to use for approximating math transform derivatives by the finite differences method.
+     */
+    protected double[] derivativeDeltas;
+
+    /**
+     * Placeholder for a GeoAPI 3.1 method which was not available in GeoAPI 3.0.
+     * This placeholder does nothing. See Apache SIS JDK6 branch for a real test.
+     *
+     * @param coordinate Ignored.
+     */
+    protected final void verifyDerivative(final double... coordinate) {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+
+    /**
+     * Placeholder for a GeoAPI 3.1 method which was not available in GeoAPI 3.0.
+     * This placeholder does nothing. See Apache SIS JDK6 branch for a real test.
+     *
+     * @param minOrdinates    Ignored.
+     * @param maxOrdinates    Ignored.
+     * @param numOrdinates    Ignored.
+     * @param randomGenerator Ignored.
+     */
+    protected final void verifyInDomain(final double[] minOrdinates, final double[] maxOrdinates,
+            final int[] numOrdinates, final Random randomGenerator)
+    {
+        // See GeoAPI 3.1 for the real test.
+        // The test is run on Apache SIS branches.
+       assumeTrue(PENDING_NEXT_GEOAPI_RELEASE); // For reporting the test as skippped.
+    }
+}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java
index e5d2975..e4b8f43 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateOperationMethods.java
@@ -50,7 +50,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.JDK8;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -249,7 +249,7 @@
          * ────────────────    EPSG IDENTIFIERS    ────────────────────────────────────
          */
         final StringBuilder buffer = new StringBuilder();
-        for (final Identifier id : method.getIdentifiers()) {
+        for (final ReferenceIdentifier id : method.getIdentifiers()) {
             if (Constants.EPSG.equalsIgnoreCase(id.getCodeSpace())) {
                 if (buffer.length() != 0) {
                     buffer.append(", ");
@@ -386,7 +386,7 @@
     private void writeName(final ParameterDescriptor<?> param) throws IOException {
         final int td = openTag("td class=\"sep\"");
         openTag("details");
-        final Identifier name = param.getName();
+        final ReferenceIdentifier name = param.getName();
         final String codeSpace = name.getCodeSpace();
         if (Constants.EPSG.equalsIgnoreCase(codeSpace)) {
             println("summary", escape(name.getCode()));
@@ -535,8 +535,8 @@
     /**
      * Returns the first EPSG code found in the given collection, or {@code null} if none.
      */
-    private static String getFirstEpsgCode(final Iterable<? extends Identifier> identifiers) {
-        for (final Identifier id : identifiers) {
+    private static String getFirstEpsgCode(final Iterable<? extends ReferenceIdentifier> identifiers) {
+        for (final ReferenceIdentifier id : identifiers) {
             if (Constants.EPSG.equalsIgnoreCase(id.getCodeSpace())) {
                 return id.getCode();
             }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateReferenceSystems.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateReferenceSystems.java
deleted file mode 100644
index 41f6b8b..0000000
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/CoordinateReferenceSystems.java
+++ /dev/null
@@ -1,910 +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.referencing.report;
-
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.Set;
-import java.util.Map;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.util.TreeMap;
-import java.io.File;
-import java.io.IOException;
-
-import org.opengis.metadata.Identifier;
-import org.opengis.util.FactoryException;
-import org.opengis.util.InternationalString;
-import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.cs.CartesianCS;
-import org.opengis.referencing.cs.SphericalCS;
-import org.opengis.referencing.cs.CoordinateSystem;
-import org.opengis.referencing.crs.CompoundCRS;
-import org.opengis.referencing.crs.VerticalCRS;
-import org.opengis.referencing.crs.GeocentricCRS;
-import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.referencing.crs.EngineeringCRS;
-import org.opengis.referencing.crs.GeneralDerivedCRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.CRSAuthorityFactory;
-import org.opengis.referencing.datum.Datum;
-import org.opengis.referencing.datum.VerticalDatumType;
-import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.test.report.AuthorityCodesReport;
-import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.internal.referencing.DeprecatedCode;
-import org.apache.sis.referencing.CRS;
-import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.referencing.IdentifiedObjects;
-import org.apache.sis.referencing.crs.AbstractCRS;
-import org.apache.sis.referencing.cs.AxesConvention;
-import org.apache.sis.util.logging.Logging;
-import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.ComparisonMode;
-import org.apache.sis.util.Deprecable;
-import org.apache.sis.util.Utilities;
-import org.apache.sis.util.Version;
-
-import static org.junit.Assert.*;
-
-// Branch-dependent imports
-import org.apache.sis.internal.jdk8.JDK8;
-
-
-/**
- * Generates a list of supported Coordinate Reference Systems in the current directory.
- * This class is for manual execution after the EPSG database has been updated,
- * or the projection implementations changed.
- *
- * <p><b>WARNING:</b>
- * this class implements heuristic rules for nicer sorting (e.g. of CRS having numbers as Roman letters).
- * Those heuristic rules were determined specifically for the EPSG dataset expanded with WMS codes.
- * This class is not likely to produce good results for any other authorities, and many need to be updated
- * after any upgrade of the EPSG dataset.</p>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.7
- * @version 0.7
- * @module
- */
-public final strictfp class CoordinateReferenceSystems extends AuthorityCodesReport {
-    /**
-     * The titles of some sections in the list of CRS. We use sections for grouping related CRS together.
-     * By default (if no mapping is specified below), the section titles will be the datum names.
-     * But in some cases we use a slightly different title. Sometime the changes are only cosmetic
-     * (e.g. "Reseau Geodesique Francais" → "Réseau Géodésique Français").
-     * But sometime the changes have the effect of merging different datums under the same section.
-     * We do that only when the datums are closely related, and the decision to merge or not is taken on a
-     * case-by-case basis. For example we merge the "Arc 1950" and "Arc 1960" sections into a single "Arc" section,
-     * since those sections were small and we do not want to scatter the HTML page with too many sections.
-     * However we do not merge "NAD83" and "NAD83(HARN)" because those sections are already quite large,
-     * and merging them will result in a too large section.
-     *
-     * <p>The decision to merge or not is arbitrary. Generally, we try to avoid small sections (less that 5 CRS)
-     * but without merging together unrelated datums.</p>
-     */
-    private static final Map<String,String> SECTION_TITLES = new HashMap<String,String>();
-    static {
-        rd("American Samoa 1962",                                         "American Samoa");
-        rd("American Samoa Vertical Datum of 2002",                       "American Samoa");
-        rd("Arc 1950",                                                    "Arc");
-        rd("Arc 1960",                                                    "Arc");
-        rd("Ancienne Triangulation Francaise (Paris)",                    "Ancienne Triangulation Française");
-        rd("Australian Geodetic Datum 1966",                              "Australian Geodetic Datum");
-        rd("Australian Geodetic Datum 1984",                              "Australian Geodetic Datum");
-        rd("Australian Height Datum (Tasmania)",                          "Australian Height Datum");
-        rd("Azores Central Islands 1948",                                 "Azores Islands");
-        rd("Azores Central Islands 1995",                                 "Azores Islands");
-        rd("Azores Occidental Islands 1939",                              "Azores Islands");
-        rd("Azores Oriental Islands 1940",                                "Azores Islands");
-        rd("Azores Oriental Islands 1995",                                "Azores Islands");
-        rd("Baltic 1980",                                                 "Baltic");
-        rd("Baltic 1982",                                                 "Baltic");
-        rd("Baltic Sea",                                                  "Baltic");
-        rd("Batavia (Jakarta)",                                           "Batavia");
-        rd("Bermuda 1957",                                                "Bermuda");
-        rd("Bermuda 2000",                                                "Bermuda");
-        rd("Bogota 1975 (Bogota)",                                        "Bogota 1975");
-        rd("Carthage (Paris)",                                            "Carthage");
-        rd("Bern 1938",                                                   "Bern / CH1903");
-        rd("Cais da Figueirinha - Angra do Heroísmo",                     "Cais");
-        rd("Cais da Madalena",                                            "Cais");
-        rd("Cais da Pontinha - Funchal",                                  "Cais");
-        rd("Cais da Vila - Porto Santo",                                  "Cais");
-        rd("Cais da Vila do Porto",                                       "Cais");
-        rd("Cais das Velas",                                              "Cais");
-        rd("Cayman Brac Vertical Datum 1961",                             "Cayman Islands");
-        rd("Cayman Islands Geodetic Datum 2011",                          "Cayman Islands");
-        rd("CH1903",                                                      "Bern / CH1903");
-        rd("CH1903+",                                                     "Bern / CH1903");
-        rd("CH1903 (Bern)",                                               "Bern / CH1903");
-        rd("Canadian Geodetic Vertical Datum of 1928",                    "Canadian Geodetic Vertical Datum");
-        rd("Canadian Geodetic Vertical Datum of 2013",                    "Canadian Geodetic Vertical Datum");
-        rd("Chatham Islands Datum 1971",                                  "Chatham Islands Datum");
-        rd("Chatham Islands Datum 1979",                                  "Chatham Islands Datum");
-        rd("Corrego Alegre 1961",                                         "Corrego Alegre");
-        rd("Corrego Alegre 1970-72",                                      "Corrego Alegre");
-        rd("Danger 1950",                                                 "Saint Pierre et Miquelon 1950");
-        rd("Dansk Normal Nul",                                            "Dansk");
-        rd("Dansk Vertikal Reference 1990",                               "Dansk");
-        rd("Dealul Piscului 1930",                                        "Dealul Piscului");
-        rd("Dealul Piscului 1970",                                        "Dealul Piscului");
-        rd("Deutsches Haupthoehennetz 1912",                              "Deutsches Haupthoehennetz");
-        rd("Deutsches Haupthoehennetz 1985",                              "Deutsches Haupthoehennetz");
-        rd("Deutsches Haupthoehennetz 1992",                              "Deutsches Haupthoehennetz");
-        rd("Douala 1948",                                                 "Douala");
-        rd("Dunedin 1958",                                                "Dunedin");
-        rd("Dunedin-Bluff 1960",                                          "Dunedin");
-        rd("EGM2008 geoid",                                               "EGM geoid");
-        rd("EGM84 geoid",                                                 "EGM geoid");
-        rd("EGM96 geoid",                                                 "EGM geoid");
-        rd("Egypt 1907",                                                  "Egypt");
-        rd("Egypt 1930",                                                  "Egypt");
-        rd("Egypt Gulf of Suez S-650 TL",                                 "Egypt");
-        rd("EPSG example  X",                                             "Seismic bin grid datum");     // 2 spaces before "X".
-        rd("Estonia 1992",                                                "Estonia");
-        rd("Estonia 1997",                                                "Estonia");
-        rd("European Datum 1950",                                         "European Datum");
-        rd("European Datum 1950(1977)",                                   "European Datum");
-        rd("European Datum 1979",                                         "European Datum");
-        rd("European Datum 1987",                                         "European Datum");
-        rd("European Vertical Reference Frame 2000",                      "European Vertical Reference Frame");
-        rd("European Vertical Reference Frame 2007",                      "European Vertical Reference Frame");
-        rd("Fahud Height Datum",                                          "Fahud");
-        rd("Fao 1979",                                                    "Fao");
-        rd("Fehmarnbelt Datum 2010",                                      "Fehmarnbelt");
-        rd("Fehmarnbelt Vertical Reference 2010",                         "Fehmarnbelt");
-        rd("Faroe Datum 1954",                                            "Faroe Islands");
-        rd("Faroe Islands Vertical Reference 2009",                       "Faroe Islands");
-        rd("fk89",                                                        "Faroe Islands");
-        rd("Fiji 1956",                                                   "Fiji");
-        rd("Fiji Geodetic Datum 1986",                                    "Fiji");
-        rd("Gan 1970",                                                    "Gandajika");
-        rd("Grand Cayman Geodetic Datum 1959",                            "Grand Cayman");
-        rd("Grand Cayman Vertical Datum 1954",                            "Grand Cayman");
-        rd("Greek (Athens)",                                              "Greek");
-        rd("Greek Geodetic Reference System 1987",                        "Greek");
-        rd("Guadeloupe 1948",                                             "Guadeloupe");
-        rd("Guadeloupe 1951",                                             "Guadeloupe");
-        rd("Guadeloupe 1988",                                             "Guadeloupe");
-        rd("Guam 1963",                                                   "Guam");
-        rd("Guam Vertical Datum of 1963",                                 "Guam");
-        rd("Guam Vertical Datum of 2004",                                 "Guam");
-        rd("Gunung Segara (Jakarta)",                                     "Gunung Segara");
-        rd("Hong Kong 1963",                                              "Hong Kong");
-        rd("Hong Kong 1963(67)",                                          "Hong Kong");
-        rd("Hong Kong 1980",                                              "Hong Kong");
-        rd("Hong Kong Chart Datum",                                       "Hong Kong");
-        rd("Hong Kong Principal Datum",                                   "Hong Kong");
-        rd("Hungarian Datum 1909",                                        "Hungarian Datum");
-        rd("Hungarian Datum 1972",                                        "Hungarian Datum");
-        rd("IGN 1962 Kerguelen",                                          "IGN");
-        rd("IGN 1966",                                                    "IGN");
-        rd("IGN 1988 LS",                                                 "IGN");
-        rd("IGN 1988 MG",                                                 "IGN");
-        rd("IGN 1988 SB",                                                 "IGN");
-        rd("IGN 1988 SM",                                                 "IGN");
-        rd("IGN 1992 LD",                                                 "IGN");
-        rd("IGN Astro 1960",                                              "IGN");
-        rd("IGN53 Mare",                                                  "IGN");
-        rd("IGN56 Lifou",                                                 "IGN");
-        rd("IGN63 Hiva Oa",                                               "IGN");
-        rd("IGN72 Grande Terre",                                          "IGN");
-        rd("IGN72 Nuku Hiva",                                             "IGN");
-        rd("Indian 1954",                                                 "Indian");
-        rd("Indian 1960",                                                 "Indian");
-        rd("Indian 1975",                                                 "Indian");
-        rd("Indian Spring Low Water",                                     "Indian");
-        rd("International Great Lakes Datum 1955",                        "International Great Lakes Datum");
-        rd("International Great Lakes Datum 1985",                        "International Great Lakes Datum");
-        rd("International Terrestrial Reference Frame 1988",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1989",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1990",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1991",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1992",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1993",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1994",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1996",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 1997",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 2000",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 2005",              "International Terrestrial Reference Frame");
-        rd("International Terrestrial Reference Frame 2008",              "International Terrestrial Reference Frame");
-        rd("Islands Net 1993",                                            "Islands Net");
-        rd("Islands Net 2004",                                            "Islands Net");
-        rd("Jamaica 1875",                                                "Jamaica");
-        rd("Jamaica 1969",                                                "Jamaica");
-        rd("Jamaica 2001",                                                "Jamaica");
-        rd("Japanese Geodetic Datum 2011 (vertical)",                     "Japanese Geodetic Datum 2011");
-        rd("Japanese Standard Levelling Datum 1969",                      "Japanese Standard Levelling Datum");
-        rd("Japanese Standard Levelling Datum 1972",                      "Japanese Standard Levelling Datum");
-        rd("Kalianpur 1880",                                              "Kalianpur");
-        rd("Kalianpur 1937",                                              "Kalianpur");
-        rd("Kalianpur 1962",                                              "Kalianpur");
-        rd("Kalianpur 1975",                                              "Kalianpur");
-        rd("Kertau (RSO)",                                                "Kertau");
-        rd("Kertau 1968",                                                 "Kertau");
-        rd("KOC Construction Datum",                                      "KOC Construction Datum / Well Datum");
-        rd("KOC Well Datum",                                              "KOC Construction Datum / Well Datum");
-        rd("Korean Datum 1985",                                           "Korean Datum");
-        rd("Korean Datum 1995",                                           "Korean Datum");
-        rd("Kuwait Oil Company",                                          "Kuwait Oil Company / Kuwait Utility");
-        rd("Kuwait PWD",                                                  "Kuwait Oil Company / Kuwait Utility");
-        rd("Kuwait Utility",                                              "Kuwait Oil Company / Kuwait Utility");
-        rd("Lao 1993",                                                    "Lao");
-        rd("Lao National Datum 1997",                                     "Lao");
-        rd("Latvia 1992",                                                 "Latvia");
-        rd("Latvian Height System 2000",                                  "Latvia");
-        rd("Lisbon 1890",                                                 "Lisbon");
-        rd("Lisbon 1890 (Lisbon)",                                        "Lisbon");
-        rd("Lisbon 1937",                                                 "Lisbon");
-        rd("Lisbon 1937 (Lisbon)",                                        "Lisbon");
-        rd("Lower Low Water Large Tide",                                  "Low Water");
-        rd("Lowest Astronomic Tide",                                      "Low Water");
-        rd("Makassar (Jakarta)",                                          "Makassar");
-        rd("Manoca 1962",                                                 "Manoca");
-        rd("Martinique 1938",                                             "Martinique");
-        rd("Martinique 1955",                                             "Martinique");
-        rd("Martinique 1987",                                             "Martinique");
-        rd("Maupiti 83",                                                  "Maupiti");
-        rd("Maupiti SAU 2001",                                            "Maupiti");
-        rd("Mean High Water",                                             "Mean Sea Level");
-        rd("Mean High Water Spring Tides",                                "Mean Sea Level");
-        rd("Mean Higher High Water",                                      "Mean Sea Level");
-        rd("Mean Low Water",                                              "Mean Sea Level");
-        rd("Mean Low Water Spring Tides",                                 "Mean Sea Level");
-        rd("Mean Lower Low Water",                                        "Mean Sea Level");
-        rd("Mean Lower Low Water Spring Tides",                           "Mean Sea Level");
-        rd("Missao Hidrografico Angola y Sao Tome 1951",                  "Missao Hidrografico Angola y Sao Tome");
-        rd("Mhast (offshore)",                                            "Missao Hidrografico Angola y Sao Tome");
-        rd("Mhast (onshore)",                                             "Missao Hidrografico Angola y Sao Tome");
-        rd("Militar-Geographische Institut (Ferro)",                      "Militar-Geographische Institut");
-        rd("Monte Mario (Rome)",                                          "Monte Mario");
-        rd("Moorea 87",                                                   "Moorea");
-        rd("Moorea SAU 1981",                                             "Moorea");
-        rd("Nahrwan 1934",                                                "Nahrwan");
-        rd("Nahrwan 1967",                                                "Nahrwan");
-        rd("Naparima 1955",                                               "Naparima");
-        rd("Naparima 1972",                                               "Naparima");
-        rd("Nivellement General de la Corse 1948",                        "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General de la France - IGN69",                    "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General de la France - IGN78",                    "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General de la France - Lallemand",                "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General de Nouvelle Caledonie",                   "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General de Polynesie Francaise",                  "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General du Luxembourg",                           "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("Nivellement General Guyanais 1977",                           "Nivellement Général Corse / France / Nouvelle-Calédonie / Polynésie Française / Luxembourd / Guyanais");
-        rd("NGO 1948 (Oslo)",                                             "NGO 1948");
-        rd("NAD83 (High Accuracy Reference Network)",                     "North American Datum 1983 — High Accuracy Reference Network");
-        rd("NAD83 (National Spatial Reference System 2007)",              "North American Datum 1983 — National Spatial Reference System 2007");
-        rd("NAD83 Canadian Spatial Reference System",                     "North American Datum 1983 — Canadian Spatial Reference System");
-        rd("Nouvelle Triangulation Francaise",                            "Nouvelle Triangulation Française");
-        rd("Nouvelle Triangulation Francaise (Paris)",                    "Nouvelle Triangulation Française");
-        rd("NAD83 (Continuously Operating Reference Station 1996)",       "North American Datum 1983 — Continuously Operating Reference Station 1996");       // For better sort order.
-        rd("NAD83 (National Spatial Reference System 2011)",              "North American Datum 1983 — National Spatial Reference System 2011");
-        rd("NAD83 (National Spatial Reference System MA11)",              "North American Datum 1983 — National Spatial Reference System MA11 / PA11");
-        rd("NAD83 (National Spatial Reference System PA11)",              "North American Datum 1983 — National Spatial Reference System MA11 / PA11");
-        rd("Norway Normal Null 1954",                                     "Norway Normal Null");
-        rd("Norway Normal Null 2000",                                     "Norway Normal Null");
-        rd("Ordnance Datum Newlyn (Orkney Isles)",                        "Ordnance Datum Newlyn");
-        rd("OSGB 1936",                                                   "OSGB");
-        rd("OSGB 1970 (SN)",                                              "OSGB");
-        rd("Padang 1884 (Jakarta)",                                       "Padang 1884");
-        rd("PDO Height Datum 1993",                                       "PDO Survey / Height Datum 1993");
-        rd("PDO Survey Datum 1993",                                       "PDO Survey / Height Datum 1993");
-        rd("Pitcairn 1967",                                               "Pitcairn");
-        rd("Pitcairn 2006",                                               "Pitcairn");
-        rd("Porto Santo 1936",                                            "Porto Santo");
-        rd("Porto Santo 1995",                                            "Porto Santo");
-        rd("Posiciones Geodésicas Argentinas 1994",                       "Posiciones Geodésicas Argentinas");
-        rd("Posiciones Geodésicas Argentinas 1998",                       "Posiciones Geodésicas Argentinas");
-        rd("Posiciones Geodésicas Argentinas 2007",                       "Posiciones Geodésicas Argentinas");
-        rd("Puerto Rico Vertical Datum of 2002",                          "Puerto Rico");
-        rd("Qatar 1948",                                                  "Qatar");
-        rd("Qatar 1974",                                                  "Qatar");
-        rd("Qatar National Datum 1995",                                   "Qatar");
-        rd("Qornoq 1927",                                                 "Qornoq");
-        rd("Reseau Geodesique Nouvelle Caledonie 1991",                   "Réseau Géodésique de Nouvelle-Calédonie");
-        rd("Reseau Geodesique de Nouvelle Caledonie 91-93",               "Réseau Géodésique de Nouvelle-Calédonie");
-        rd("Reseau National Belge 1950",                                  "Réseau National Belge");
-        rd("Reseau National Belge 1950 (Brussels)",                       "Réseau National Belge");
-        rd("Reseau National Belge 1972",                                  "Réseau National Belge");
-        rd("Reunion 1947",                                                "Réunion");
-        rd("Reunion 1989",                                                "Réunion");
-        rd("Rikets hojdsystem 1900",                                      "Rikets hojdsystem");
-        rd("Rikets hojdsystem 1970",                                      "Rikets hojdsystem");
-        rd("Rikets hojdsystem 2000",                                      "Rikets hojdsystem");
-        rd("Santa Cruz da Graciosa",                                      "Santa Cruz");
-        rd("Santa Cruz das Flores",                                       "Santa Cruz");
-        rd("Sierra Leone 1968",                                           "Sierra Leone");
-        rd("Sierra Leone Colony 1924",                                    "Sierra Leone");
-        rd("SIRGAS-Chile",                                                "SIRGAS");
-        rd("SIRGAS-ROU98",                                                "SIRGAS");
-        rd("SIRGAS_ES2007.8",                                             "SIRGAS");
-        rd("South American Datum 1969",                                   "South American Datum");
-        rd("South American Datum 1969(96)",                               "South American Datum");
-        rd("Sri Lanka Datum 1999",                                        "Sri Lanka");
-        rd("Sri Lanka Vertical Datum",                                    "Sri Lanka");
-        rd("Stockholm 1938 (Stockholm)",                                  "Stockholm 1938");
-        rd("Systém Jednotné Trigonometrické Síte Katastrální (Ferro)",    "Systém Jednotné Trigonometrické Síte Katastrální");
-        rd("Systém Jednotné Trigonometrické Síte Katastrální/05",         "Systém Jednotné Trigonometrické Síte Katastrální");
-        rd("Systém Jednotné Trigonometrické Síte Katastrální/05 (Ferro)", "Systém Jednotné Trigonometrické Síte Katastrální");
-        rd("Tahaa 54",                                                    "Tahaa");
-        rd("Tahaa SAU 2001",                                              "Tahaa");
-        rd("Tahiti 52",                                                   "Tahiti");
-        rd("Tahiti 79",                                                   "Tahiti");
-        rd("Taiwan Datum 1967",                                           "Taiwan Datum");
-        rd("Taiwan Datum 1997",                                           "Taiwan Datum");
-        rd("Tananarive 1925 (Paris)",                                     "Tananarive 1925");
-        rd("Tokyo 1892",                                                  "Tokyo");
-        rd("Viti Levu 1912",                                              "Viti Levu");
-        rd("Voirol 1875",                                                 "Voirol");
-        rd("Voirol 1875 (Paris)",                                         "Voirol");
-        rd("Voirol 1879",                                                 "Voirol");
-        rd("Voirol 1879 (Paris)",                                         "Voirol");
-        rd("WGS 72 Transit Broadcast Ephemeris",                          "World Geodetic System 1972 — Transit Broadcast Ephemeris");
-        rd("Yellow Sea 1956",                                             "Yellow Sea");
-        rd("Yellow Sea 1985",                                             "Yellow Sea");
-    }
-
-    /**
-     * The datums from the above list which are deprecated, but that we do not want to replace by the non-deprecated
-     * datum. We disable some replacements when they allow better sorting of deprecated CRS.
-     */
-    private static final Set<String> KEEP_DEPRECATED_DATUM = new HashSet<String>(Arrays.asList(
-        "Dealul Piscului 1970"));           // Datum does not exist but is an alias for S-42 in Romania.
-
-    /**
-     * Shortcut for {@link #SECTION_TITLES} initialization.
-     * {@code "rd"} stands for "rename datum".
-     */
-    private static void rd(final String datum, final String display) {
-        assertNull(datum, SECTION_TITLES.put(datum, display));
-    }
-
-    /**
-     * Words to ignore in a datum name in order to detect if a CRS name is the acronym of the datum name.
-     */
-    private static final Set<String> DATUM_WORDS_TO_IGNORE = new HashSet<String>(Arrays.asList(
-            "of",           // VIVD:   Virgin Islands Vertical Datum of 2009
-            "de",           // RRAF:   Reseau de Reference des Antilles Francaises
-            "des",          // RGAF:   Reseau Geodesique des Antilles Francaises
-            "la",           // RGR:    Reseau Geodesique de la Reunion
-            "et",           // RGSPM:  Reseau Geodesique de Saint Pierre et Miquelon
-            "para",         // SIRGAS: Sistema de Referencia Geocentrico para America del Sur 1995
-            "del",          // SIRGAS: Sistema de Referencia Geocentrico para America del Sur 1995
-            "las",          // SIRGAS: Sistema de Referencia Geocentrico para las AmericaS 2000
-            "Tides"));      // MLWS:   Mean Low Water Spring Tides
-
-    /**
-     * The keywords before which to cut the CRS names when sorting by alphabetical order.
-     * The main intend here is to preserve the "far west", "west", "central west", "central",
-     * "central east", "east", "far east" order.
-     */
-    private static final String[] CUT_BEFORE = {
-        " far west",        // "MAGNA-SIRGAS / Colombia Far West zone"
-        " far east",
-        " west",            // "Bogota 1975 / Colombia West zone"
-        " east",            // "Bogota 1975 / Colombia East Central zone"
-        " central",         // "Korean 1985 / Central Belt" (between "East Belt" and "West Belt")
-        " old central",     // "NAD Michigan / Michigan Old Central"
-        " bogota zone",     // "Bogota 1975 / Colombia Bogota zone"
-        // Do not declare "North" and "South" as it causes confusion with "WGS 84 / North Pole" and other cases.
-    };
-
-    /**
-     * The keywords after which to cut the CRS names when sorting by alphabetical order.
-     *
-     * Note: alphabetical sorting of Roman numbers work for zones from I to VIII inclusive.
-     * If there is more zones (for example with "JGD2000 / Japan Plane Rectangular"), then
-     * we need to cut before those numbers in order to use sorting by EPSG codes instead.
-     *
-     * Note 2: if alphabetical sorting is okay for Roman numbers, it is actually preferable
-     * because it give better position of names with height like "zone II + NGF IGN69 height".
-     */
-    private static final String[] CUT_AFTER = {
-        " cs ",                     // "JGD2000 / Japan Plane Rectangular CS IX"
-        " tm",                      // "ETRS89 / TM35FIN(E,N)" — we want to not interleave them between "TM35" and "TM36".
-        " dktm",                    // "ETRS89 / DKTM1 + DVR90 height"
-        "-gk",                      // "ETRS89 / ETRS-GK19FIN"
-//      " philippines zone ",       // "Luzon 1911 / Philippines zone IV"
-//      " california zone ",        // "NAD27 / California zone V"
-//      " ngo zone ",               // "NGO 1948 (Oslo) / NGO zone I"
-//      " lambert zone ",           // "NTF (Paris) / Lambert zone II + NGF IGN69 height"
-        "fiji 1956 / utm zone "     // Two zones: 60S and 1S with 60 before 1.
-    };
-
-    /**
-     * The symbol to write in from of EPSG code of CRS having an axis order different
-     * then the (longitude, latitude) one.
-     */
-    private static final char YX_ORDER = '\u21B7';
-
-    /**
-     * The factory which create CRS instances.
-     */
-    private final CRSAuthorityFactory factory;
-
-    /**
-     * The datum from the {@link #SECTION_TITLES} that we didn't found after we processed all codes.
-     * Used for verification purpose only.
-     */
-    private final Set<String> unusedDatumMapping;
-
-    /**
-     * Creates a new instance.
-     */
-    private CoordinateReferenceSystems() throws FactoryException {
-        super(null);
-        unusedDatumMapping = new HashSet<String>(SECTION_TITLES.keySet());
-        properties.setProperty("TITLE",           "Apache SIS™ Coordinate Reference System (CRS) codes");
-        properties.setProperty("PRODUCT.NAME",    "Apache SIS™");
-        properties.setProperty("PRODUCT.VERSION", getVersion());
-        properties.setProperty("PRODUCT.URL",     "http://sis.apache.org");
-        properties.setProperty("JAVADOC.GEOAPI",  "http://www.geoapi.org/snapshot/javadoc");
-        properties.setProperty("FACTORY.NAME",    "EPSG");
-        properties.setProperty("FACTORY.VERSION", "8.9");
-        properties.setProperty("FACTORY.VERSION.SUFFIX", ", together with other sources");
-        properties.setProperty("DESCRIPTION", "<p><b>Notation:</b></p>\n" +
-                "<ul>\n" +
-                "  <li>The " + YX_ORDER + " symbol in front of authority codes (${PERCENT.ANNOTATED} of them) identifies" +
-                " left-handed coordinate systems (for example with <var>latitude</var> axis before <var>longitude</var>).</li>\n" +
-                "  <li>The <del>codes with a strike</del> (${PERCENT.DEPRECATED} of them) identify deprecated CRS." +
-                " In some cases, the remarks column indicates the replacement.</li>\n" +
-                "</ul>");
-        factory = org.apache.sis.referencing.CRS.getAuthorityFactory(null);
-        add(factory);
-    }
-
-    /**
-     * Generates the HTML report.
-     *
-     * @param  args Ignored.
-     * @throws FactoryException If an error occurred while fetching the CRS.
-     * @throws IOException If an error occurred while writing the HTML file.
-     */
-    @SuppressWarnings("UseOfSystemOutOrSystemErr")
-    public static void main(final String[] args) throws FactoryException, IOException {
-        Locale.setDefault(Locale.US);   // We have to use this hack for now because exceptions are formatted in the current locale.
-        final CoordinateReferenceSystems writer = new CoordinateReferenceSystems();
-        final File file = writer.write(new File("CoordinateReferenceSystems.html"));
-        System.out.println("Created " + file.getAbsolutePath());
-        if (!writer.unusedDatumMapping.isEmpty()) {
-            System.out.println();
-            System.out.println("WARNING: the following datums were expected but not found. Maybe their spelling changed?");
-            for (final String name : writer.unusedDatumMapping) {
-                System.out.print("  - ");
-                System.out.println(name);
-            }
-        }
-    }
-
-    /**
-     * Returns the current Apache SIS version, with the {@code -SNAPSHOT} trailing part omitted.
-     *
-     * @return The current Apache SIS version.
-     */
-    private static String getVersion() {
-        String version = Version.SIS.toString();
-        final int snapshot = version.lastIndexOf('-');
-        if (snapshot >= 2) {
-            version = version.substring(0, snapshot);
-        }
-        return version;
-    }
-
-    /**
-     * Creates the text to show in the "Remarks" column for the given CRS.
-     */
-    private String getRemark(final CoordinateReferenceSystem crs) {
-        if (crs instanceof GeographicCRS) {
-            return (crs.getCoordinateSystem().getDimension() == 3) ? "Geographic 3D" : "Geographic";
-        }
-        if (crs instanceof GeneralDerivedCRS) {
-            final OperationMethod method = ((GeneralDerivedCRS) crs).getConversionFromBase().getMethod();
-            return "<a href=\"CoordinateOperationMethods.html#"
-                   + IdentifiedObjects.getIdentifier(method, Citations.EPSG).getCode()
-                   + "\">" + method.getName().getCode().replace('_', ' ') + "</a>";
-        }
-        if (crs instanceof GeocentricCRS) {
-            final CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs instanceof CartesianCS) {
-                return "Geocentric (Cartesian coordinate system)";
-            } else if (cs instanceof SphericalCS) {
-                return "Geocentric (spherical coordinate system)";
-            }
-            return "Geocentric";
-        }
-        if (crs instanceof VerticalCRS) {
-            final VerticalDatumType type = ((VerticalCRS) crs).getDatum().getVerticalDatumType();
-            return CharSequences.camelCaseToSentence(type.name().toLowerCase(getLocale())) + " height";
-        }
-        if (crs instanceof CompoundCRS) {
-            final StringBuilder buffer = new StringBuilder();
-            for (final CoordinateReferenceSystem component : ((CompoundCRS) crs).getComponents()) {
-                if (buffer.length() != 0) {
-                    buffer.append(" + ");
-                }
-                buffer.append(getRemark(component));
-            }
-            return buffer.toString();
-        }
-        if (crs instanceof EngineeringCRS) {
-            return "Engineering (" + crs.getCoordinateSystem().getName().getCode() + ')';
-        }
-        return "";
-    }
-
-    /**
-     * Omits the trailing number, if any.
-     * For example if the given name is "Abidjan 1987", then this method returns "Abidjan".
-     */
-    private static String omitTrailingNumber(String name) {
-        int i = CharSequences.skipTrailingWhitespaces(name, 0, name.length());
-        while (i != 0) {
-            final char c = name.charAt(--i);
-            if (c < '0' || c > '9') {
-                name = name.substring(0, CharSequences.skipTrailingWhitespaces(name, 0, i+1));
-                break;
-            }
-        }
-        return name;
-    }
-
-    /**
-     * If the first word of the CRS name seems to be an acronym of the datum name,
-     * puts that acronym in a {@code <abbr title="datum name">...</abbr>} element.
-     */
-    static String insertAbbreviationTitle(final String crsName, final String datumName) {
-        int s = crsName.indexOf(' ');
-        if (s < 0) s = crsName.length();
-        int p = crsName.indexOf('(');
-        if (p >= 0 && p < s) s = p;
-        p = datumName.indexOf('(');
-        if (p < 0) p = datumName.length();
-        final String acronym = crsName.substring(0, s);
-        final String ar = omitTrailingNumber(acronym);
-        final String dr = omitTrailingNumber(datumName.substring(0, p));
-        if (dr.startsWith(ar)) {
-            return crsName;                                 // Avoid redudancy between CRS name and datum name.
-        }
-        /*
-         * If the first CRS word does not seem to be an acronym of the datum name, verify
-         * if there is some words that we should ignore in the datum name and try again.
-         */
-        if (!CharSequences.isAcronymForWords(ar, dr)) {
-            final String[] words = (String[]) CharSequences.split(dr, ' ');
-            int n = 0;
-            for (final String word : words) {
-                if (!DATUM_WORDS_TO_IGNORE.contains(word)) {
-                    words[n++] = word;
-                }
-            }
-            if (n == words.length || n < 2) {
-                return crsName;
-            }
-            final StringBuilder b = new StringBuilder();
-            for (int i=0; i<n; i++) {
-                if (i != 0) b.append(' ');
-                b.append(words[i]);
-            }
-            if (!CharSequences.isAcronymForWords(ar, b)) {
-                return crsName;
-            }
-        }
-        return "<abbr title=\"" + datumName + "\">" + acronym + "</abbr>" + crsName.substring(s);
-    }
-
-    /**
-     * Invoked when a CRS has been successfully created. This method modifies the default
-     * {@link org.opengis.test.report.AuthorityCodesReport.Row} attribute values created
-     * by GeoAPI.
-     *
-     * @param  code    The authority code of the created object.
-     * @param  object  The object created from the given authority code.
-     * @return The created row, or {@code null} if the row should be ignored.
-     */
-    @Override
-    protected Row createRow(final String code, final IdentifiedObject object) {
-        final Row row = super.createRow(code, object);
-        final CoordinateReferenceSystem crs = (CoordinateReferenceSystem) object;
-        final CoordinateReferenceSystem crsXY = AbstractCRS.castOrCopy(crs).forConvention(AxesConvention.RIGHT_HANDED);
-        if (!Utilities.deepEquals(crs.getCoordinateSystem(), crsXY.getCoordinateSystem(), ComparisonMode.IGNORE_METADATA)) {
-            row.annotation = YX_ORDER;
-        }
-        CoordinateReferenceSystem replacement = crs;
-        row.remark = getRemark(crs);
-        /*
-         * If the object is deprecated, find the replacement.
-         * We do not take the whole comment because it may be pretty long.
-         */
-        if (object instanceof Deprecable) {
-            row.isDeprecated = ((Deprecable) object).isDeprecated();
-            if (row.isDeprecated) {
-                String replacedBy = null;
-                InternationalString i18n = object.getRemarks();
-                for (final Identifier id : object.getIdentifiers()) {
-                    if (id instanceof Deprecable && ((Deprecable) id).isDeprecated()) {
-                        i18n = ((Deprecable) id).getRemarks();
-                        if (id instanceof DeprecatedCode) {
-                            replacedBy = ((DeprecatedCode) id).replacedBy;
-                        }
-                        break;
-                    }
-                }
-                if (i18n != null) {
-                    row.remark = i18n.toString(getLocale());
-                }
-                /*
-                 * If a replacement exists for a deprecated CRS, use the datum of the replacement instead than
-                 * the datum of the deprecated CRS for determining in which section to put the CRS. The reason
-                 * is that some CRS are deprecated because they were associated to the wrong datum, in which
-                 * case the deprecated CRS would appear in the wrong section if we do not apply this correction.
-                 */
-                if (!KEEP_DEPRECATED_DATUM.contains(CRS.getSingleComponents(crs).get(0).getDatum().getName().getCode())) {
-                    if (replacedBy != null) try {
-                        replacement = factory.createCoordinateReferenceSystem("EPSG:" + replacedBy);
-                    } catch (FactoryException e) {
-                        // Ignore - keep the datum of the deprecated object.
-                    }
-                }
-            }
-        }
-        ((ByName) row).setup(CRS.getSingleComponents(replacement).get(0).getDatum(), unusedDatumMapping);
-        return row;
-    }
-
-    /**
-     * Invoked when a CRS creation failed. This method modifies the default
-     * {@link org.opengis.test.report.AuthorityCodesReport.Row} attribute values
-     * created by GeoAPI.
-     *
-     * @param  code      The authority code of the object to create.
-     * @param  exception The exception that occurred while creating the identified object.
-     * @return The created row, or {@code null} if the row should be ignored.
-     */
-    @Override
-    protected Row createRow(final String code, final FactoryException exception) {
-        final Row row = super.createRow(code, exception);
-        try {
-            row.name = factory.getDescriptionText(code).toString(getLocale());
-        } catch (FactoryException e) {
-            Logging.unexpectedException(null, CoordinateReferenceSystems.class, "createRow", e);
-        }
-        if (code.startsWith("AUTO2:")) {
-            // It is normal to be unable to instantiate an "AUTO" CRS,
-            // because those authority codes need parameters.
-            row.hasError = false;
-            row.remark = "Projected";
-            ((ByName) row).setup(CommonCRS.WGS84.datum(), unusedDatumMapping);
-        } else {
-            row.remark = exception.getMessage();
-            ((ByName) row).setup(null, unusedDatumMapping);
-        }
-        return row;
-    }
-
-    /**
-     * Invoked by {@link AuthorityCodesReport} for creating a new row instance.
-     *
-     * @return The new row instance.
-     */
-    @Override
-    protected Row newRow() {
-        return new ByName();
-    }
-
-
-
-
-    /**
-     * A row with an natural ordering that use the first part of the name before to use the authority code.
-     * We use only the part of the name prior some keywords (e.g. {@code "zone"}).
-     * For example if the following codes:
-     *
-     * {@preformat text
-     *    EPSG:32609    WGS 84 / UTM zone 9N
-     *    EPSG:32610    WGS 84 / UTM zone 10N
-     * }
-     *
-     * We compare only the "WGS 84 / UTM" string, then the code. This is a reasonably easy way to keep a more
-     * natural ordering ("9" sorted before "10", "UTM North" projections kept together and same for South).
-     */
-    private static final class ByName extends Row {
-        /**
-         * A string derived from the {@link #name} to use for sorting.
-         */
-        private String reducedName;
-
-        /**
-         * The datum name, or {@code null} if unknown.
-         * If non-null, this is used for grouping CRS names by sections.
-         */
-        String section;
-
-        /**
-         * Creates a new row.
-         */
-        ByName() {
-        }
-
-        /**
-         * Computes the {@link #reducedName} field value.
-         */
-        final void setup(final Datum datum, final Set<String> unusedDatumMapping) {
-            final String datumName;
-            if (datum != null) {
-                datumName = datum.getName().getCode();
-            } else {
-                // Temporary patch (TODO: remove after we implemented the missing methods in SIS)
-                if (name.startsWith("NSIDC EASE-Grid")) {
-                    datumName = "Unspecified datum";
-                } else if (code.equals("EPSG:2163")) {
-                    datumName = "Unspecified datum";
-                } else if (code.equals("EPSG:5818")) {
-                    datumName = "Seismic bin grid datum";
-                } else {
-                    datumName = null;       // Keep ordering based on the name.
-                }
-            }
-            section = JDK8.getOrDefault(SECTION_TITLES, datumName, datumName);
-            unusedDatumMapping.remove(datumName);
-            /*
-             * Get a copy of the name in all lower case.
-             */
-            final StringBuilder b = new StringBuilder(name);
-            for (int i=0; i<b.length(); i++) {
-                b.setCharAt(i, Character.toLowerCase(b.charAt(i)));
-            }
-            /*
-             * Cut the string to a shorter length if we find a keyword.
-             * This will result in many string equals, which will then be sorted by EPSG codes.
-             * This is useful when the EPSG codes give a better ordering than the alphabetic one
-             * (for example with Roman numbers).
-             */
-            int s = 0;
-            for (final String keyword : CUT_BEFORE) {
-                int i = b.lastIndexOf(keyword);
-                if (i > 0 && (s == 0 || i < s)) s = i;
-            }
-            for (final String keyword : CUT_AFTER) {
-                int i = b.lastIndexOf(keyword);
-                if (i >= 0) {
-                    i += keyword.length();
-                    if (i > s) s = i;
-                }
-            }
-            if (s != 0) b.setLength(s);
-            uniformizeZoneNumber(b);
-            reducedName = b.toString();
-            if (datumName != null) {
-                name = insertAbbreviationTitle(name, datumName);
-            }
-        }
-
-        /**
-         * If the string ends with a number optionally followed by "N" or "S", replaces the hemisphere
-         * symbol by a sign and makes sure that the number uses at least 3 digits (e.g. "2N" → "+002").
-         * This string will be used for better sorting order.
-         */
-        private static void uniformizeZoneNumber(final StringBuilder b) {
-            if (b.indexOf("/") < 0) {
-                /*
-                 * Do not process names like "WGS 84". We want to process only names like "WGS 84 / UTM zone 2N",
-                 * otherwise the replacement of "WGS 84" by "WGS 084" causes unexpected sorting.
-                 */
-                return;
-            }
-            int  i = b.length();
-            char c = b.charAt(i - 1);
-            if (c == ')') {
-                // Ignore suffix like " (ftUS)".
-                i = b.lastIndexOf(" (");
-                if (i < 0) return;
-                c = b.charAt(i - 1);
-            }
-            char sign;
-            switch (c) {
-                default:            sign =  0;       break;
-                case 'e': case 'n': sign = '+'; i--; break;
-                case 'w': case 's': sign = '-'; i--; break;
-            }
-            int upper = i;
-            do {
-                if (i == 0) return;
-                c = b.charAt(--i);
-            } while (c >= '0' && c <= '9');
-            switch (upper - ++i) {
-                case 2: b.insert(i,  '0'); upper++;  break;     // Found 2 digits.
-                case 1: b.insert(i, "00"); upper+=2; break;     // Only one digit found.
-                case 0: return;                                 // No digit.
-            }
-            if (sign != 0) {
-                b.insert(i, sign);
-                upper++;
-            }
-            b.setLength(upper);
-        }
-
-        /**
-         * Compares this row with the given row for ordering by name.
-         */
-        @Override
-        public int compareTo(final Row o) {
-            int n = reducedName.compareTo(((ByName) o).reducedName);
-            if (n == 0) {
-                n = super.compareTo(o);
-            }
-            return n;
-        }
-    }
-
-    /**
-     * Sorts the rows, then inserts sections between CRS instances that use different datums.
-     */
-    @Override
-    protected void sortRows() {
-        super.sortRows();
-        @SuppressWarnings("SuspiciousToArrayCall")
-        final ByName[] data = rows.toArray(new ByName[rows.size()]);
-        final Map<String,String> sections = new TreeMap<String,String>();
-        for (final ByName row : data) {
-            final String section = row.section;
-            if (section != null) {
-                sections.put(CharSequences.toASCII(section).toString().toLowerCase(), section);
-            }
-        }
-        rows.clear();
-        /*
-         * Recopy the rows, but section-by-section. We do this sorting here instead than in the Row.compareTo(Row)
-         * method in order to preserve the alphabetical order of rows with unknown datum.
-         * Algorithm below is inefficient, but this class should be rarely used anyway and only by site maintainer.
-         */
-        for (final String section : sections.values()) {
-            final Row separator = new Row();
-            separator.isSectionHeader = true;
-            separator.name = section;
-            rows.add(separator);
-            boolean found = false;
-            for (int i=0; i<data.length; i++) {
-                final ByName row = data[i];
-                if (row != null) {
-                    if (row.section != null) {
-                        found = section.equals(row.section);
-                    }
-                    if (found) {
-                        rows.add(row);
-                        data[i] = null;
-                        found = true;
-                    }
-                }
-            }
-        }
-        boolean found = false;
-        for (final ByName row : data) {
-            if (row != null) {
-                if (!found) {
-                    final Row separator = new Row();
-                    separator.isSectionHeader = true;
-                    separator.name = "Unknown";
-                    rows.add(separator);
-                }
-                rows.add(row);
-                found = true;
-            }
-        }
-    }
-}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java b/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
index 160ee18..2309fd5 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
@@ -28,6 +28,7 @@
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.cs.AxisDirection;
@@ -75,7 +76,7 @@
      *
      * @since 0.6
      */
-    public static void assertOgcIdentifierEquals(final String expected, final Identifier actual) {
+    public static void assertOgcIdentifierEquals(final String expected, final ReferenceIdentifier actual) {
         assertNotNull(actual);
         assertEquals("code",       expected,      actual.getCode());
         assertEquals("codeSpace",  Constants.OGC, actual.getCodeSpace());
@@ -96,7 +97,7 @@
     public static void assertEpsgIdentifierEquals(final String expected, final Identifier actual) {
         assertNotNull(actual);
         assertEquals("code",       expected,        actual.getCode());
-        assertEquals("codeSpace",  Constants.EPSG,  actual.getCodeSpace());
+        assertEquals("codeSpace",  Constants.EPSG,  (actual instanceof ReferenceIdentifier) ? ((ReferenceIdentifier) actual).getCodeSpace() : null);
         assertEquals("authority",  Constants.EPSG,  Citations.getIdentifier(actual.getAuthority()));
         assertEquals("identifier", Constants.EPSG + DefaultNameSpace.DEFAULT_SEPARATOR + expected,
                 IdentifiedObjects.toString(actual));
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
index 6ad3acb..ff00d8a 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/ConsistencyTest.java
@@ -83,7 +83,7 @@
      */
     @Test
     public void testCoordinateReferenceSystems() throws FactoryException {
-        assumeTrue("Extensive tests not enabled.", RUN_EXTENSIVE_TESTS);
+        assumeTrue(RUN_EXTENSIVE_TESTS);
         final WKTFormat v1  = new WKTFormat(null, null);
         final WKTFormat v1c = new WKTFormat(null, null);
         final WKTFormat v2  = new WKTFormat(null, null);
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 3a85d2d..be8ac41 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
@@ -88,6 +88,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.StandardCharsets;
+import org.apache.sis.internal.geoapi.evolution.UnsupportedCodeList;
 
 
 /**
@@ -143,6 +144,18 @@
     }
 
     /**
+     * Creates a telephone number of the given type.
+     *
+     * @param type Either {@code "VOICE"}, {@code "FACSIMILE"} or {@code "SMS"}.
+     */
+    private static DefaultTelephone telephone(final String number, final String type) {
+        final DefaultTelephone tel = new DefaultTelephone();
+        tel.setNumber(number);
+        tel.setNumberType(UnsupportedCodeList.valueOf(type));
+        return tel;
+    }
+
+    /**
      * Programmatically creates the metadata to marshall, or to compare against the unmarshalled metadata.
      *
      * @return The hard-coded representation of {@code "Metadata.xml"} content.
@@ -160,7 +173,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/"));
@@ -168,11 +181,11 @@
             final DefaultContact contact = new DefaultContact(online);
             contact.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "IFREMER");
             contact.setPhones(Arrays.asList(
-                    new DefaultTelephone("+33 (0)2 xx.xx.xx.x6", TelephoneType.VOICE),
-                    new DefaultTelephone("+33 (0)2 xx.xx.xx.x4", TelephoneType.FACSIMILE)
+                    telephone("+33 (0)2 xx.xx.xx.x6", "VOICE"),
+                    telephone("+33 (0)2 xx.xx.xx.x4", "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);
@@ -192,16 +205,16 @@
                     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);
                 contact.setPhones(Arrays.asList(
-                        new DefaultTelephone("+33 (0)4 xx.xx.xx.x5", TelephoneType.VOICE),
-                        new DefaultTelephone("+33 (0)4 xx.xx.xx.x8", TelephoneType.FACSIMILE)
+                        telephone("+33 (0)4 xx.xx.xx.x5", "VOICE"),
+                        telephone("+33 (0)4 xx.xx.xx.x8", "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);
@@ -216,7 +229,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));
             }
@@ -248,7 +261,7 @@
              */
             {
                 final DefaultLegalConstraints constraint = new DefaultLegalConstraints();
-                constraint.setAccessConstraints(singleton(Restriction.LICENCE));
+                constraint.setAccessConstraints(singleton(Restriction.LICENSE));
                 identification.setResourceConstraints(singleton(constraint));
             }
             /*
@@ -256,14 +269,14 @@
              */
             {
                 @SuppressWarnings("deprecation")
-                final DefaultAssociatedResource aggregateInfo = new DefaultAggregateInformation();
+                final DefaultAggregateInformation aggregateInfo = new DefaultAggregateInformation();
                 final DefaultCitation name = new DefaultCitation("MEDIPROD VI");
                 name.setAlternateTitles(singleton(new SimpleInternationalString("90008411")));
                 name.setDates(singleton(new DefaultCitationDate(TestUtilities.date("1990-06-04 22:00:00"), DateType.REVISION)));
                 aggregateInfo.setName(name);
                 aggregateInfo.setInitiativeType(InitiativeType.CAMPAIGN);
-                aggregateInfo.setAssociationType(AssociationType.LARGER_WORK_CITATION);
-                identification.setAssociatedResources(singleton(aggregateInfo));
+                aggregateInfo.setAssociationType(AssociationType.LARGER_WORD_CITATION); // There is a typo ("WORD" → "WORK"), but we have to use the wrong spelling for this branch.
+                identification.setAggregationInfo(singleton(aggregateInfo));
             }
             /*
              * Data indentification / Extent.
@@ -343,7 +356,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)));
@@ -358,7 +371,7 @@
             onlines.setProtocol("http");
             transfer.setOnLines(singleton(onlines));
             distributionInfo.setTransferOptions(singleton(transfer));
-            metadata.setDistributionInfo(singleton(distributionInfo));
+            metadata.setDistributionInfo(distributionInfo);
         }
         return metadata;
     }
@@ -395,6 +408,7 @@
                      "<gmx:Anchor xlink:href=\"SDN:L231:3:CDI\">Common Data Index record</gmx:Anchor>");
         replace(xml, "<gco:CharacterString>EPSG:4326</gco:CharacterString>",
                      "<gmx:Anchor xlink:href=\"SDN:L101:2:4326\">EPSG:4326</gmx:Anchor>");
+        replace(xml, "License", "Licence");
         /*
          * The <gmd:EX_TemporalExtent> block can not be marshalled yet, since it requires the sis-temporal module.
          * We need to instruct the XML comparator to ignore this block during the comparison. We also ignore for
@@ -451,10 +465,10 @@
     @Test
     public void testMetadataWithVerticalCRS() throws JAXBException {
         final Metadata metadata = unmarshalFile(Metadata.class, VERTICAL_CRS_XML);
-        assertEquals("fileIdentifier", "20090901",                     metadata.getMetadataIdentifier().getCode());
-        assertEquals("language",       Locale.ENGLISH,                 getSingleton(metadata.getLanguages()));
-        assertEquals("characterSet",   StandardCharsets.UTF_8,         getSingleton(metadata.getCharacterSets()));
-        assertEquals("dateStamp",      xmlDate("2014-01-04 00:00:00"), getSingleton(metadata.getDateInfo()).getDate());
+        assertEquals("fileIdentifier", "20090901",                     metadata.getFileIdentifier());
+        assertEquals("language",       Locale.ENGLISH,                 metadata.getLanguage());
+        assertEquals("characterSet",   CharacterSet.UTF_8,             metadata.getCharacterSet());
+        assertEquals("dateStamp",      xmlDate("2014-01-04 00:00:00"), metadata.getDateStamp());
         /*
          * <gmd:contact>
          *   <gmd:CI_ResponsibleParty>
@@ -462,13 +476,10 @@
          *   </gmd:CI_ResponsibleParty>
          * </gmd:contact>
          */
-        final Responsibility contact        = getSingleton(metadata   .getContacts());
-        final Party          party          = getSingleton(contact    .getParties());
-        final Contact        contactInfo    = getSingleton(party      .getContactInfo());
-        final OnlineResource onlineResource = getSingleton(contactInfo.getOnlineResources());
-        assertInstanceOf("party", Organisation.class, party);
+        final ResponsibleParty contact = getSingleton(metadata.getContacts());
+        final OnlineResource onlineResource = contact.getContactInfo().getOnlineResource();
         assertNotNull("onlineResource", onlineResource);
-        assertEquals("organisationName", "Apache SIS", party.getName().toString());
+        assertEquals("organisationName", "Apache SIS", contact.getOrganisationName().toString());
         assertEquals("linkage", URI.create("http://sis.apache.org"), onlineResource.getLinkage());
         assertEquals("function", OnLineFunction.INFORMATION, onlineResource.getFunction());
         assertEquals("role", Role.PRINCIPAL_INVESTIGATOR, contact.getRole());
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
index 081e003..a540f95 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
@@ -181,28 +181,11 @@
 
     // Direct (not from authority codes) geodetic object creations.
     org.apache.sis.referencing.StandardDefinitionsTest.class,
-    org.apache.sis.referencing.factory.GeodeticObjectFactoryTest.class,
-    org.apache.sis.referencing.factory.GIGS3002.class,
-    org.apache.sis.referencing.factory.GIGS3003.class,
-    org.apache.sis.referencing.factory.GIGS3004.class,
-    org.apache.sis.referencing.factory.GIGS3005.class,
 
     // Well Known Text parsing require above factory.
     org.apache.sis.io.wkt.MathTransformParserTest.class,
     org.apache.sis.io.wkt.GeodeticObjectParserTest.class,
     org.apache.sis.io.wkt.WKTFormatTest.class,
-    org.apache.sis.io.wkt.WKTParserTest.class,
-
-    // Geodetic object creations from authority codes.
-    org.apache.sis.referencing.factory.GIGS2001.class,
-    org.apache.sis.referencing.factory.GIGS2002.class,
-    org.apache.sis.referencing.factory.GIGS2003.class,
-    org.apache.sis.referencing.factory.GIGS2004.class,
-    org.apache.sis.referencing.factory.GIGS2005.class,
-    org.apache.sis.referencing.factory.GIGS2006.class,
-    org.apache.sis.referencing.factory.GIGS2007.class,
-    org.apache.sis.referencing.factory.GIGS2008.class,
-    org.apache.sis.referencing.factory.GIGS2009.class,
 
     // Following tests use indirectly EPSG factory.
     org.apache.sis.referencing.CommonCRSTest.class,
diff --git a/core/sis-utility/pom.xml b/core/sis-utility/pom.xml
index b6a9283..4b0b801 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeList.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeList.java
new file mode 100644
index 0000000..4d372a3
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeList.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 desruisseaux.
+ *
+ * Licensed 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.geoapi.evolution;
+
+import java.util.List;
+import java.util.ArrayList;
+import org.opengis.util.CodeList;
+
+
+/**
+ * Placeholder for code list not yet available in GeoAPI.
+ * Example: {@code org.opengis.metadata.citation.TelephoneType}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+public final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 7205015191869240829L;
+
+    /**
+     * The list of constants defined in this code list.
+     */
+    private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+
+    /**
+     * A frequently used code list element.
+     */
+    public static final CodeList<?> VOICE = new UnsupportedCodeList("VOICE");
+
+    /**
+     * A frequently used code list element.
+     */
+    public static final CodeList<?> FACSIMILE = new UnsupportedCodeList("FACSIMILE");
+
+    /**
+     * Constructor for new code list element.
+     *
+     * @param name The code list name.
+     */
+    private UnsupportedCodeList(String name) {
+        super(name, VALUES);
+    }
+
+    /**
+     * Returns the list of codes of the same kind than this code list element.
+     *
+     * @return All code values for this code list.
+     */
+    @Override
+    public UnsupportedCodeList[] family() {
+        synchronized (VALUES) {
+            return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+        }
+    }
+
+    /**
+     * Returns the telephone type that matches the given string, or returns a new one if none match it.
+     *
+     * @param code The name of the code to fetch or to create.
+     * @return A code matching the given name.
+     */
+    public static UnsupportedCodeList valueOf(String code) {
+        return valueOf(UnsupportedCodeList.class, code);
+    }
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeListAdapter.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeListAdapter.java
new file mode 100644
index 0000000..5e35960
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/UnsupportedCodeListAdapter.java
@@ -0,0 +1,165 @@
+/*
+ * 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.geoapi.evolution;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.util.CodeList;
+import org.apache.sis.util.iso.Types;
+import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.internal.jaxb.gmd.CodeListUID;
+
+
+/**
+ * An adapter for {@link UnsupportedCodeList}, in order to implement the ISO-19139 standard.
+ * See {@link org.apache.sis.internal.jaxb.gmd.CodeListAdapter} for more information.
+ *
+ * @param <ValueType> The subclass implementing this adapter.
+ *
+ * @author  Cédric Briançon (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+public abstract class UnsupportedCodeListAdapter<ValueType extends UnsupportedCodeListAdapter<ValueType>>
+        extends XmlAdapter<ValueType,CodeList<?>>
+{
+    /**
+     * The value of the {@link CodeList}.
+     */
+    protected CodeListUID identifier;
+
+    /**
+     * Empty constructor for subclasses only.
+     */
+    protected UnsupportedCodeListAdapter() {
+    }
+
+    /**
+     * Creates a wrapper for a {@link CodeList}, in order to handle the format specified in ISO-19139.
+     *
+     * @param value The value of the {@link CodeList} to be marshalled.
+     */
+    protected UnsupportedCodeListAdapter(final CodeListUID value) {
+        identifier = value;
+    }
+
+    /**
+     * Wraps the code into an adapter.
+     * Most implementations will be like below:
+     *
+     * {@preformat java
+     *     return new ValueType(value);
+     * }
+     *
+     * @param value The value of {@link CodeList} to be marshalled.
+     * @return The wrapper for the code list value.
+     */
+    protected abstract ValueType wrap(CodeListUID value);
+
+    /**
+     * Returns the name of the code list class.
+     *
+     * @return The code list class name.
+     */
+    protected abstract String getCodeListName();
+
+    /**
+     * Substitutes the adapter value read from an XML stream by the object which will
+     * contains the value. JAXB calls automatically this method at unmarshalling time.
+     *
+     * @param  adapter The adapter for this metadata value.
+     * @return A code list which represents the metadata value.
+     */
+    @Override
+    public final CodeList<?> unmarshal(final ValueType adapter) {
+        if (adapter == null) {
+            return null;
+        }
+        return Types.forCodeName(UnsupportedCodeList.class, adapter.identifier.toString(), true);
+    }
+
+    /**
+     * Substitutes the code list by the adapter to be marshalled into an XML file or stream.
+     * JAXB calls automatically this method at marshalling time.
+     *
+     * @param  value The code list value.
+     * @return The adapter for the given code list.
+     */
+    @Override
+    public final ValueType marshal(final CodeList<?> value) {
+        if (value == null) {
+            return null;
+        }
+        final String name = value.name();
+        final int length = name.length();
+        final StringBuilder buffer = new StringBuilder(length);
+        final String codeListValue = toIdentifier(name, buffer, false);
+        buffer.setLength(0);
+        return wrap(new CodeListUID(Context.current(), getCodeListName(), codeListValue,
+                null, toIdentifier(name, buffer, true)));
+    }
+
+    /**
+     * Converts the given Java constant name to something hopefully close to the UML identifier,
+     * or close to the textual value to put in the XML. This method convert the Java constant name
+     * to camel case if {@code isValue} is {@code true}, or to lower cases with word separated by
+     * spaces if {@code isValue} is {@code true}.
+     *
+     * @param  name    The Java constant name (e.g. {@code WEB_SERVICES}).
+     * @param  buffer  An initially empty buffer to use for creating the identifier.
+     * @param  isValue {@code false} for the {@code codeListValue} attribute, or {@code true} for the XML value.
+     * @return The identifier (e.g. {@code "webServices"} or {@code "Web services"}).
+     */
+    protected String toIdentifier(final String name, final StringBuilder buffer, final boolean isValue) {
+        final int length = name.length();
+        boolean toUpper = isValue;
+        for (int i=0; i<length;) {
+            int c = name.codePointAt(i);
+            i += Character.charCount(c);
+            if (c == '_') {
+                if (isValue) {
+                    c = ' ';
+                } else {
+                    toUpper = true;
+                    continue;
+                }
+            }
+            if (toUpper) {
+                c = Character.toUpperCase(c);
+                toUpper = false;
+            } else {
+                c = Character.toLowerCase(c);
+            }
+            buffer.appendCodePoint(c);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Invoked by JAXB on marshalling. Subclasses must override this
+     * method with the appropriate {@code @XmlElement} annotation.
+     *
+     * @return The {@code CodeList} value to be marshalled.
+     */
+    public abstract CodeListUID getElement();
+
+    /*
+     * We do not define setter method (even abstract) since it seems to confuse JAXB.
+     * It is subclasses responsibility to define the setter method.
+     */
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/package-info.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/package-info.java
new file mode 100644
index 0000000..364d706
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/package-info.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides a transition path for new GeoAPI elements not yet published in a formal release.
+ * We try to avoid putting a copy of those new elements in Apache SIS, since it would break
+ * compatibility when they would be removed in favor of GeoAPI elements. The approach taken
+ * is rather to use in the new API the most immediate parent available in a GeoAPI release.
+ * For example for new code list classes, this is {@code CodeList<?>}. The Javadoc for such
+ * API shall contain a warning. See {@code warning-templates.txt} for some proposals.
+ *
+ * <p><STRONG>Do not use!</STRONG></p>
+ *
+ * This package is for internal use by SIS only. Classes in this package
+ * may change in incompatible ways in any future version without notice.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.5
+ * @version 0.5
+ * @module
+ */
+package org.apache.sis.internal.geoapi.evolution;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/warning-templates.txt b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/warning-templates.txt
new file mode 100644
index 0000000..b81aad9
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/evolution/warning-templates.txt
@@ -0,0 +1,33 @@
+Suggestions for the Javadoc of methods having a CodeList<?> return type
+(replace "NewCodeList" and "3.1" by appropriate values):
+
+     *
+     * <div class="warning"><b>Upcoming API change — specialization</b><br>
+     * The argument type will be changed to the {@code NewCodeList} code list when GeoAPI will provide it
+     * (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
+     *
+     * {@preformat java
+     *   final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
+     *       private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
+     *
+     *       // Need to declare at least one code list element.
+     *       public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
+     *
+     *       private UnsupportedCodeList(String name) {
+     *           super(name, VALUES);
+     *       }
+     *
+     *       public static UnsupportedCodeList valueOf(String code) {
+     *           return valueOf(UnsupportedCodeList.class, code);
+     *       }
+     *
+     *       &#64;Override
+     *       public UnsupportedCodeList[] family() {
+     *           synchronized (VALUES) {
+     *               return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
+     *           }
+     *       }
+     *   }
+     * }
+     * </div>
+     *
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Instant.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Instant.java
new file mode 100644
index 0000000..7305594
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Instant.java
@@ -0,0 +1,38 @@
+/*
+ * 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.geoapi.temporal;
+
+import java.util.Date;
+import org.opengis.temporal.TemporalPrimitive;
+
+
+/**
+ * Placeholder for a GeoAPI interfaces not present in GeoAPI 3.0.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.5
+ * @module
+ */
+public interface Instant extends TemporalPrimitive {
+    /**
+     * Gets the date of this instant.
+     *
+     * @return The date.
+     */
+    Date getDate();
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Period.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Period.java
new file mode 100644
index 0000000..bcee105
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Period.java
@@ -0,0 +1,44 @@
+/*
+ * 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.geoapi.temporal;
+
+import org.opengis.temporal.TemporalPrimitive;
+
+
+/**
+ * Placeholder for a GeoAPI interfaces not present in GeoAPI 3.0.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public interface Period extends TemporalPrimitive {
+    /**
+     * Links this period to the instant at which it ends.
+     *
+     * @return The beginning instant.
+     */
+    Instant getBeginning();
+
+    /**
+     * Links this period to the instant at which it ends.
+     *
+     * @return The end instant.
+     */
+    Instant getEnding();
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/PeriodDuration.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/PeriodDuration.java
new file mode 100644
index 0000000..433b61d
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/PeriodDuration.java
@@ -0,0 +1,69 @@
+/*
+ * 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.geoapi.temporal;
+
+import org.opengis.util.InternationalString;
+
+
+/**
+ * Placeholder for a GeoAPI interfaces which is still incomplete in GeoAPI 3.0.0.
+ * We reproduce here the GeoAPI 3.1-pending API. Note that at the time of writing,
+ * this is a bad API (values shall not be instances of {@link InternationalString}).
+ * This will be fixed in a future GeoAPI version.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public interface PeriodDuration extends org.opengis.temporal.PeriodDuration {
+    /**
+     * A positive integer, followed by the character "Y",
+     * which indicated the number of years in the period.
+     */
+    InternationalString getYears();
+
+    /**
+     * A positive integer, followed by the character "M",
+     * which indicated the number of months in the period.
+     */
+    InternationalString getMonths();
+
+    /**
+     * A positive integer, followed by the character "D",
+     * which indicated the number of days in the period.
+     */
+    InternationalString getDays();
+
+    /**
+     * A positive integer, followed by the character "H",
+     * which indicated the number of hours in the period.
+     */
+    InternationalString getHours();
+
+    /**
+     * A positive integer, followed by the character "M",
+     * which indicated the number of minutes in the period.
+     */
+    InternationalString getMinutes();
+
+    /**
+     * A positive integer, followed by the character "S",
+     * which indicated the number of seconds in the period.
+     */
+    InternationalString getSeconds();
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Position.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Position.java
new file mode 100644
index 0000000..6fb8687
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/Position.java
@@ -0,0 +1,37 @@
+/*
+ * 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.geoapi.temporal;
+
+import java.util.Date;
+
+
+/**
+ * Placeholder for a GeoAPI interfaces not present in GeoAPI 3.0.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public interface Position {
+    /**
+     * Returns the time value as a {@code Date} object.
+     *
+     * @return The temporal value.
+     */
+    Date getDate();
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/TemporalFactory.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/TemporalFactory.java
new file mode 100644
index 0000000..e904ada
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/TemporalFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.geoapi.temporal;
+
+import java.util.Date;
+import org.opengis.util.InternationalString;
+
+
+/**
+ * Placeholder for a GeoAPI interfaces not present in GeoAPI 3.0.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public interface TemporalFactory {
+    Instant createInstant(Date date);
+
+    Period createPeriod(Instant begin, Instant end);
+
+    PeriodDuration createPeriodDuration(InternationalString years, InternationalString months,
+            InternationalString week, InternationalString days, InternationalString hours,
+            InternationalString minutes, InternationalString seconds);
+}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/package-info.java b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/package-info.java
new file mode 100644
index 0000000..a1fe891
--- /dev/null
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/geoapi/temporal/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * Placeholder for GeoAPI interfaces not present in GeoAPI 3.0.0.
+ *
+ * <STRONG>Do not use!</STRONG>
+ *
+ * This package is for internal use by SIS only. Classes in this package
+ * may change in incompatible ways in any future version without notice.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+package org.apache.sis.internal.geoapi.temporal;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapEntry.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapEntry.java
index 4bbca52..b8ac1d2 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapEntry.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapEntry.java
@@ -19,8 +19,6 @@
 import java.util.AbstractMap;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.util.InternationalString;
-import org.apache.sis.internal.util.Citations;
 
 
 /**
@@ -32,7 +30,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.5
+ * @version 0.3
  * @module
  */
 final class IdentifierMapEntry extends AbstractMap.SimpleEntry<Citation,String> implements Identifier {
@@ -65,42 +63,6 @@
     }
 
     /**
-     * Infers a code space from the authority.
-     *
-     * @return The code space, or {@code null} if none.
-     *
-     * @since 0.5
-     */
-    @Override
-    public String getCodeSpace() {
-        return Citations.getCodeSpace(getAuthority());
-    }
-
-    /**
-     * Returns {@code null} since this class does not hold version information.
-     *
-     * @return {@code null}.
-     *
-     * @since 0.5
-     */
-    @Override
-    public String getVersion() {
-        return null;
-    }
-
-    /**
-     * Returns {@code null} since this class does not hold natural language description.
-     *
-     * @return {@code null}.
-     *
-     * @since 0.5
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
      * Same than the above, but as an immutable entry. We use this implementation when the
      * entry has been created on-the-fly at iteration time rather than being stored in the
      * identifier collection.
@@ -108,10 +70,7 @@
     static final class Immutable extends AbstractMap.SimpleImmutableEntry<Citation,String> implements Identifier {
         private static final long serialVersionUID = -6857931598565368465L;
         Immutable(Citation authority, String code) {super(authority, code);}
-        @Override public Citation            getAuthority()   {return getKey();}
-        @Override public String              getCode()        {return getValue();}
-        @Override public String              getCodeSpace()   {return Citations.getCodeSpace(getAuthority());}
-        @Override public String              getVersion()     {return null;}
-        @Override public InternationalString getDescription() {return null;}
+        @Override public Citation getAuthority()   {return getKey();}
+        @Override public String   getCode()        {return getValue();}
     }
 }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
index e4e83ed..89337b7 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
@@ -23,7 +23,6 @@
 import java.util.logging.Level;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.util.InternationalString;
 import org.apache.sis.xml.XLink;
 import org.apache.sis.xml.IdentifierMap;
 import org.apache.sis.xml.IdentifierSpace;
@@ -188,42 +187,6 @@
     }
 
     /**
-     * Infers a code space from the authority.
-     *
-     * @return The code space, or {@code null} if none.
-     *
-     * @since 0.5
-     */
-    @Override
-    public String getCodeSpace() {
-        return Citations.getCodeSpace(authority);
-    }
-
-    /**
-     * Returns {@code null} since this class does not hold version information.
-     *
-     * @return {@code null}.
-     *
-     * @since 0.5
-     */
-    @Override
-    public String getVersion() {
-        return null;
-    }
-
-    /**
-     * Returns {@code null} since this class does not hold natural language description.
-     *
-     * @return {@code null}.
-     *
-     * @since 0.5
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
      * Returns a hash code value for this identifier.
      */
     @Override
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java
index 0dbcdc6..05f3932 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gco/GO_CharacterString.java
@@ -26,7 +26,6 @@
 import javax.xml.bind.annotation.XmlSeeAlso;
 import org.w3c.dom.Element;
 import org.opengis.util.CodeList;
-import org.opengis.util.ControlledVocabulary;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.gmx.Anchor;
@@ -241,7 +240,7 @@
         if (type != ENUM) {
             return null;
         }
-        final ControlledVocabulary code = Types.forCodeTitle(text);
+        final CodeList<?> code = Types.forCodeTitle(text);
         final String name = Types.getListName(code);
         final String namespace;
         /*
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java
index dc540dc..e3a89ea 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java
@@ -115,7 +115,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 {@link 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-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListUID.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListUID.java
index bb05a23..9be2a5d 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListUID.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListUID.java
@@ -23,7 +23,6 @@
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlValue;
 import org.opengis.util.CodeList;
-import org.opengis.util.ControlledVocabulary;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.Schemas;
@@ -104,7 +103,7 @@
     /**
      * Default empty constructor for JAXB.
      */
-    private CodeListUID() {
+    CodeListUID() {
     }
 
     /**
@@ -132,7 +131,7 @@
      * @param context The current (un)marshalling context, or {@code null} if none.
      * @param code    The code list to wrap.
      */
-    public CodeListUID(final Context context, final ControlledVocabulary code) {
+    public CodeListUID(final Context context, final CodeList<?> code) {
         final String classID = Types.getListName(code);
         final String fieldID = Types.getCodeName(code);
         codeList = schema(context, classID);
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/EnumAdapter.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/EnumAdapter.java
deleted file mode 100644
index 02a7c24..0000000
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/EnumAdapter.java
+++ /dev/null
@@ -1,90 +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.jaxb.gmd;
-
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.opengis.util.ControlledVocabulary;
-import org.apache.sis.util.iso.Types;
-
-
-/**
- * An adapter for {@link Enum}, in order to implement the ISO-19139 standard.
- * Example:
- *
- * {@preformat xml
- *   <srv:direction>
- *     <srv:SV_ParameterDirection>in</srv:SV_ParameterDirection>
- *   </srv:direction>
- * }
- *
- * @param <ValueType> The subclass implementing this adapter.
- * @param <BoundType> The enum being adapted.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.5
- * @version 0.6
- * @module
- */
-public abstract class EnumAdapter<ValueType extends EnumAdapter<ValueType,BoundType>,
-        BoundType extends Enum<BoundType>> extends XmlAdapter<ValueType,BoundType>
-{
-    /**
-     * For subclass constructors.
-     */
-    protected EnumAdapter() {
-    }
-
-    /**
-     * Converts the given XML value to an enumeration constant name.
-     *
-     * @param  value The text in the XML element.
-     * @return The presumed enumeration constant name.
-     */
-    protected static String name(final String value) {
-        /*
-         * Replace space ! " # $ % & ' ( ) * + , - . / punction characters by '_'.
-         * For example this replace "in/out" by "IN_OUT" in ParameterDirection.
-         *
-         * Note: we do not use codepoint API because this method is mostly for
-         * GeoAPI programmatic constant names, which are written in English.
-         */
-        final int length = value.length();
-        final StringBuilder buffer = new StringBuilder(length);
-        for (int i=0; i<length; i++) {
-            char c = value.charAt(i);
-            if (c < '0') {
-                c = '_';
-            } else if (!Character.isUpperCase(c)) {
-                c = Character.toUpperCase(c);
-            } else if (i != 0) {
-                buffer.append('_');
-            }
-            buffer.append(c);
-        }
-        return buffer.toString();
-    }
-
-    /**
-     * Returns the text to write in the XML element for the given enumeration constant.
-     *
-     * @param  e The enumeration constant.
-     * @return The text to write in the XML element.
-     */
-    protected static String value(final ControlledVocabulary e) {
-        return Types.getCodeName(e);
-    }
-}
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java
index efbeaf3..a175e6f 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java
@@ -18,8 +18,6 @@
 
 import java.util.Date;
 import javax.xml.bind.annotation.XmlElement;
-import org.opengis.temporal.Period;
-import org.opengis.temporal.Instant;
 import org.opengis.temporal.TemporalPrimitive;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.XmlUtilities;
@@ -27,6 +25,10 @@
 import org.apache.sis.internal.util.TemporalUtilities;
 import org.apache.sis.util.resources.Errors;
 
+// Branch-dependent imports
+import org.apache.sis.internal.geoapi.temporal.Period;
+import org.apache.sis.internal.geoapi.temporal.Instant;
+
 
 /**
  * JAXB adapter for {@link TemporalPrimitive}, in order to integrate the value in an element complying
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimeInstant.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimeInstant.java
index 022b86b..56cdf07 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimeInstant.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimeInstant.java
@@ -22,10 +22,13 @@
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.datatype.XMLGregorianCalendar;
 import javax.xml.datatype.DatatypeConfigurationException;
-import org.opengis.temporal.Instant;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.XmlUtilities;
 
+// Branch-dependent imports
+import org.apache.sis.internal.geoapi.temporal.Instant;
+import org.apache.sis.internal.geoapi.temporal.Position;
+
 
 /**
  * Encapsulates a {@code gml:TimeInstant}. This element may be used alone, or included in a
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriod.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriod.java
index de0fe51..2213575 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriod.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriod.java
@@ -20,11 +20,13 @@
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElements;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.temporal.Period;
 import org.apache.sis.internal.jaxb.Context;
 
 import static org.apache.sis.internal.jaxb.LegacyNamespaces.VERSION_3_0;
 
+// Branch-dependent imports
+import org.apache.sis.internal.geoapi.temporal.Period;
+
 
 /**
  * The adapter for {@code "TimePeriod"}. This is an attribute of {@link TM_Primitive}.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriodBound.java b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriodBound.java
index 7c2ff46..d2687ec 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriodBound.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TimePeriodBound.java
@@ -21,7 +21,9 @@
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.datatype.XMLGregorianCalendar;
-import org.opengis.temporal.Instant;
+
+// Branch-dependent imports
+import org.apache.sis.internal.geoapi.temporal.Instant;
 
 
 /**
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/CitationConstant.java b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
index f1707e4..eb52f0f 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
@@ -21,11 +21,9 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 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;
 import org.apache.sis.util.Debug;
 import org.apache.sis.xml.IdentifierSpace;
@@ -158,12 +156,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 Collection<? extends OnlineResource>       getOnlineResources()         {return delegate().getOnlineResources();}
-    @Override public Collection<? extends BrowseGraphic>        getGraphics()                {return delegate().getGraphics();}
+    @Override public InternationalString                        getOtherCitationDetails()    {return delegate().getOtherCitationDetails();}
     @Override public String                                     getISBN()                    {return delegate().getISBN();}
     @Override public String                                     getISSN()                    {return delegate().getISSN();}
 
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java
index a86a05b..654e5b0 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleAttributeType.java
@@ -16,12 +16,8 @@
  */
 package org.apache.sis.internal.simple;
 
-import java.util.Map;
-import java.util.Collections;
 import java.io.Serializable;
 import org.opengis.util.Type;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.util.TypeName;
@@ -39,7 +35,7 @@
  * @version 0.5
  * @module
  */
-public final class SimpleAttributeType<V> implements AttributeType<V>, Type, Serializable {
+public final class SimpleAttributeType<V> implements Type, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -71,7 +67,6 @@
      *
      * @return The name of this attribute type.
      */
-    @Override
     public GenericName getName() {
         return name;
     }
@@ -91,7 +86,6 @@
      *
      * @return The class of value for attributes of this type.
      */
-    @Override
     public Class<V> getValueClass() {
         return valueClass;
     }
@@ -101,7 +95,6 @@
      *
      * @return Always 1.
      */
-    @Override
     public int getMinimumOccurs() {
         return 1;
     }
@@ -111,7 +104,6 @@
      *
      * @return Always 1.
      */
-    @Override
     public int getMaximumOccurs() {
         return 1;
     }
@@ -121,7 +113,6 @@
      *
      * @return Always {@code null}.
      */
-    @Override
     public V getDefaultValue() {
         return null;
     }
@@ -131,7 +122,6 @@
      *
      * @return Always {@code null}.
      */
-    @Override
     public InternationalString getDefinition() {
         return null;
     }
@@ -141,7 +131,6 @@
      *
      * @return Always {@code null}.
      */
-    @Override
     public InternationalString getDesignation() {
         return null;
     }
@@ -151,30 +140,11 @@
      *
      * @return Always {@code null}.
      */
-    @Override
     public InternationalString getDescription() {
         return null;
     }
 
     /**
-     * Not used for this simple attribute type.
-     *
-     * @return Always empty.
-     */
-    @Override
-    public Map<String, AttributeType<?>> characteristics() {
-        return Collections.emptyMap();
-    }
-
-    /**
-     * Unsupported operation.
-     */
-    @Override
-    public Attribute<V> newInstance() {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
      * Returns a hash code value for this type.
      *
      * @return A hash code value.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
index 52af8d5..7c48eb1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
@@ -23,11 +23,9 @@
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 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;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.util.Debug;
@@ -91,12 +89,10 @@
     @Override public InternationalString                        getEdition()                 {return null;}
     @Override public Date                                       getEditionDate()             {return null;}
     @Override public Collection<? extends Identifier>           getIdentifiers()             {return Collections.emptyList();}
-    @Override public Collection<? extends Responsibility>       getCitedResponsibleParties() {return Collections.emptyList();}
+    @Override public Collection<? extends ResponsibleParty>     getCitedResponsibleParties() {return Collections.emptyList();}
     @Override public Collection<PresentationForm>               getPresentationForms()       {return Collections.emptyList();}
     @Override public Series                                     getSeries()                  {return null;}
-    @Override public Collection<? extends InternationalString>  getOtherCitationDetails()    {return Collections.emptyList();}
-    @Override public Collection<? extends OnlineResource>       getOnlineResources()         {return Collections.emptyList();}
-    @Override public Collection<? extends BrowseGraphic>        getGraphics()                {return Collections.emptyList();}
+    @Override public InternationalString                        getOtherCitationDetails()    {return null;}
     @Override public String                                     getISBN()                    {return null;}
     @Override public String                                     getISSN()                    {return null;}
     @Deprecated
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
index 540e6e8..529eb0e 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
@@ -26,6 +26,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.util.Citations;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.LenientComparable;
@@ -57,7 +58,7 @@
     /**
      * The primary name by which this object is identified.
      */
-    protected Identifier name;
+    protected ReferenceIdentifier name;
 
     /**
      * Creates an identified object without identifier.
@@ -80,7 +81,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;
     }
 
@@ -90,7 +91,7 @@
      * @return The identifier given at construction time.
      */
     @Override
-    public Identifier getName() {
+    public ReferenceIdentifier getName() {
         return name;
     }
 
@@ -104,7 +105,7 @@
      * @return The identifiers, or an empty set if none.
      */
     @Override
-    public final Set<Identifier> getIdentifiers() {
+    public final Set<ReferenceIdentifier> getIdentifiers() {
         return Collections.emptySet();
     }
 
@@ -234,7 +235,7 @@
     public String toString() {
         final String code, codespace;
         final Citation authority;
-        final Identifier name = this.name;
+        final ReferenceIdentifier name = this.name;
         if (name != null) {
             code      = name.getCode();
             codespace = name.getCodeSpace();
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
index 67a1061..03a2dec 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
@@ -20,6 +20,7 @@
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Citations;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Classes;
@@ -43,7 +44,7 @@
  * @version 0.6
  * @module
  */
-public class SimpleIdentifier implements Identifier, Deprecable, Serializable {
+public class SimpleIdentifier implements ReferenceIdentifier, Deprecable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -146,18 +147,6 @@
     }
 
     /**
-     * Returns a natural language description of the meaning of the code value.
-     *
-     * @return Natural language description, or {@code null} if none.
-     *
-     * @since 0.5
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
      * An optional free text.
      *
      * @since 0.6
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/system/Supervisor.java b/core/sis-utility/src/main/java/org/apache/sis/internal/system/Supervisor.java
index a5f0496..2f59144 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/system/Supervisor.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/system/Supervisor.java
@@ -61,7 +61,7 @@
      *
      * @see <a href="http://sis.apache.org/branches.html#trunk">Differences between SIS trunk and branches</a>
      */
-    static final boolean ENABLED = true;
+    static final boolean ENABLED = false;
 
     /**
      * The JMX object name for the {@code Supervisor} service.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
index 45ca7e6..1813963 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
@@ -32,6 +32,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -256,10 +257,10 @@
             while (identifiers.hasNext()) {
                 final Identifier id = identifiers.next();
                 if (id != null && equalsFiltered(code, id.getCode())) {
-                    if (identifier != null) {
-                        final String codeSpace = identifier.getCodeSpace();
-                        if (codeSpace != null) {
-                            final String cs = id.getCodeSpace();
+                    if (identifier instanceof ReferenceIdentifier) {
+                        final String codeSpace = ((ReferenceIdentifier) identifier).getCodeSpace();
+                        if (codeSpace != null && id instanceof ReferenceIdentifier) {
+                            final String cs = ((ReferenceIdentifier) id).getCodeSpace();
                             if (cs != null) {
                                 return equalsFiltered(codeSpace, cs);
                             }
@@ -289,8 +290,8 @@
                 return identifierMatches(authority, other);
             }
         }
-        if (codeSpace != null) {
-            final String other = identifier.getCodeSpace();
+        if (codeSpace != null && identifier instanceof ReferenceIdentifier) {
+            final String other = ((ReferenceIdentifier) identifier).getCodeSpace();
             if (other != null) {
                 return CharSequences.equalsFiltered(codeSpace, other, Characters.Filter.UNICODE_IDENTIFIER, true);
             }
@@ -320,7 +321,7 @@
             boolean hasFound = false;
             for (final Identifier identifier : id1) {
                 final Citation authority = identifier.getAuthority();
-                final String   codeSpace = identifier.getCodeSpace();
+                final String codeSpace = (identifier instanceof ReferenceIdentifier) ? ((ReferenceIdentifier) identifier).getCodeSpace() : null;
                 for (final Identifier other : id2) {
                     if (authorityMatches(identifier, authority, codeSpace)) {
                         if (CharSequences.equalsFiltered(identifier.getCode(), other.getCode(), Characters.Filter.UNICODE_IDENTIFIER, true)) {
@@ -373,7 +374,8 @@
                          * Unicode identifiers. If a codespace exists, then the code does not need to begin
                          * with a "Unicode identifier start" (it may be a "Unicode identifier part").
                          */
-                        String cs = CharSequences.trimWhitespaces(id.getCodeSpace());
+                        String cs = (id instanceof ReferenceIdentifier)
+                                    ? CharSequences.trimWhitespaces(((ReferenceIdentifier) id).getCodeSpace()) : null;
                         if (cs == null || cs.isEmpty()) {
                             cs = null;
                             isUnicode = CharSequences.isUnicodeIdentifier(candidate);
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/TemporalUtilities.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/TemporalUtilities.java
index dfe89aa..f109eb1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/TemporalUtilities.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/TemporalUtilities.java
@@ -17,9 +17,9 @@
 package org.apache.sis.internal.util;
 
 import java.util.Date;
-import org.opengis.temporal.Instant;
-import org.opengis.temporal.Period;
-import org.opengis.temporal.TemporalFactory;
+import org.apache.sis.internal.geoapi.temporal.Instant;
+import org.apache.sis.internal.geoapi.temporal.Period;
+import org.apache.sis.internal.geoapi.temporal.TemporalFactory;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -45,7 +45,7 @@
      *
      * @see <a href="http://sis.apache.org/branches.html#trunk">Differences between SIS trunk and branches</a>
      */
-    public static final boolean REPORT_MISSING_MODULE = true;
+    public static final boolean REPORT_MISSING_MODULE = false;
 
     /**
      * Do not allow instantiation of this class.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/io/IdentifiedObjectFormat.java b/core/sis-utility/src/main/java/org/apache/sis/io/IdentifiedObjectFormat.java
index 87b095b..bc484fa 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/io/IdentifiedObjectFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/io/IdentifiedObjectFormat.java
@@ -21,8 +21,8 @@
 import java.text.FieldPosition;
 import java.text.ParsePosition;
 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.Citations;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.resources.Vocabulary;
@@ -59,7 +59,7 @@
      */
     @Override
     public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-        final Identifier identifier = ((IdentifiedObject) obj).getName();
+        final ReferenceIdentifier identifier = ((IdentifiedObject) obj).getName();
         if (identifier == null) {
             return toAppendTo.append(Vocabulary.getResources(locale).getString(Vocabulary.Keys.Unnamed));
         }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/io/LineAppender.java b/core/sis-utility/src/main/java/org/apache/sis/io/LineAppender.java
index 0fe557b..6d70b9a 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/io/LineAppender.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/io/LineAppender.java
@@ -282,7 +282,6 @@
      *
      * @param  lineSeparator The new line separator, or {@code null} for forwarding EOL <i>as-is</i>.
      *
-     * @see System#lineSeparator()
      * @see Characters#isLineOrParagraphSeparator(int)
      */
     public void setLineSeparator(final String lineSeparator) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java b/core/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java
index 63879a7..6842a44 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/io/TabularFormat.java
@@ -215,7 +215,7 @@
      *   <li>If present, {@code '?'} shall be the first character in the pattern.</li>
      *   <li>The repeated character (specified inside the pair of brackets) is mandatory.</li>
      *   <li>In the current implementation, the repeated character must be in the
-     *       {@linkplain Character#isBmpCodePoint(int) Basic Multilanguage Plane}.</li>
+     *       Basic Multilanguage Plane.</li>
      *   <li>If {@code '/'} is present, anything on its right side shall be compliant
      *       with the {@link Pattern} syntax.</li>
      * </ul>
diff --git a/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java b/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
index 392efa5..89e8243 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
@@ -126,7 +126,7 @@
      *   <tr><td>{@code "CREATE"}</td> <td>Creates a new storage object (file or database) if it does not exist.</td></tr>
      * </table>
      *
-     * {@section Differences between the JDK6 and JDK7 branches of SIS}
+     * <div class="section">Differences between the JDK6 and JDK7 branches of SIS</div>
      * In the JDK7 branch of SIS, the array type for this key is {@code java.nio.file.OpenOption[]} instead than
      * {@code Object[]} and the constants listed in the above table are {@code java.nio.file.StandardOpenOption}
      * enumeration values.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
index e06e12f..2b49629 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
@@ -28,11 +28,11 @@
 import java.text.ParsePosition;
 import java.text.ParseException;
 import java.util.regex.Matcher;
+import org.opengis.util.CodeList;
 import java.nio.charset.Charset;
 import org.opengis.util.Type;
 import org.opengis.util.Record;
 import org.opengis.util.GenericName;
-import org.opengis.util.ControlledVocabulary;
 import org.opengis.util.InternationalString;
 import org.apache.sis.io.LineAppender;
 import org.apache.sis.io.TableAppender;
@@ -662,8 +662,8 @@
                 text = ((InternationalString) value).toString(getDisplayLocale());
             } else if (value instanceof CharSequence) {
                 text = value.toString();
-            } else if (value instanceof ControlledVocabulary) {
-                text = Types.getCodeTitle((ControlledVocabulary) value).toString(getDisplayLocale());
+            } else if (value instanceof CodeList<?>) {
+                text = Types.getCodeTitle((CodeList<?>) value).toString(getDisplayLocale());
             } else if (value instanceof Enum<?>) {
                 text = CharSequences.upperCaseToSentence(((Enum<?>) value).name());
             } else if (value instanceof Type) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractInternationalString.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractInternationalString.java
index 9fecd56..8ac8adc 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractInternationalString.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/AbstractInternationalString.java
@@ -20,7 +20,6 @@
 import java.util.Formatter;
 import java.util.Formattable;
 import java.util.FormattableFlags;
-import org.opengis.util.ControlledVocabulary;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.util.Utilities;
 import org.apache.sis.util.CharSequences;
@@ -40,7 +39,7 @@
  * by a {@link org.opengis.util.CodeList} value. This can be done with:
  *
  * <ul>
- *   <li>{@link Types#getCodeTitle(ControlledVocabulary)} for getting the {@link InternationalString}
+ *   <li>{@link Types#getCodeTitle(CodeList)} for getting the {@link InternationalString}
  *       instance to store in a metadata property.</li>
  *   <li>{@link Types#forCodeTitle(CharSequence)} for retrieving the {@link org.opengis.util.CodeList}
  *       previously stored as an {@code InternationalString}.</li>
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
index eca7d4a..2614e56 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultNameFactory.java
@@ -225,7 +225,6 @@
      * @param  attributeType The type of the data associated with the record member.
      * @return The member name for the given character sequence.
      */
-    @Override
     public MemberName createMemberName(final NameSpace scope, final CharSequence name, final TypeName attributeType) {
         return pool.unique(new DefaultMemberName(scope, name, attributeType));
     }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java
index 170699e..e0e8dd3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordSchema.java
@@ -29,7 +29,6 @@
 import org.opengis.util.NameSpace;
 import org.opengis.util.RecordSchema;
 import org.opengis.util.RecordType;
-import org.opengis.feature.AttributeType;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ObjectConverter;
@@ -82,14 +81,13 @@
     /**
      * The factory to use for creating names.
      * This is the factory given at construction time.
+     *
+     * <div class="warning"><b>Upcoming API change</b> — generalization<br>
+     * This field type will be changed to the {@link NameFactory} interface when that interface
+     * will provide a {@code createMemberName(…)} method (tentatively in GeoAPI 3.1).
+     * </div>
      */
-    protected final NameFactory nameFactory;
-
-    /**
-     * The helper class to use for mapping Java classes to {@code TypeName} instances, or {@code null} if not needed.
-     * This helper class is needed only if {@link #nameFactory} is not an instance of {@link DefaultNameFactory}.
-     */
-    private final TypeNames typeFactory;
+    protected final DefaultNameFactory nameFactory;
 
     /**
      * The namespace of {@link RecordType} to be created by this class.
@@ -121,17 +119,21 @@
     /**
      * Creates a new schema of the given name.
      *
+     * <div class="warning"><b>Upcoming API change</b> — generalization<br>
+     * This type of the first argument will be changed to the {@link NameFactory} interface when
+     * that interface will provide a {@code createMemberName(…)} method (tentatively in GeoAPI 3.1).
+     * </div>
+     *
      * @param nameFactory The factory to use for creating names, or {@code null} for the default factory.
      * @param parent      The parent namespace, or {@code null} if none.
      * @param schemaName  The name of the new schema.
      */
-    public DefaultRecordSchema(NameFactory nameFactory, final NameSpace parent, final CharSequence schemaName) {
+    public DefaultRecordSchema(DefaultNameFactory nameFactory, final NameSpace parent, final CharSequence schemaName) {
         ArgumentChecks.ensureNonNull("schemaName", schemaName);
         if (nameFactory == null) {
-            nameFactory = DefaultFactories.forBuildin(NameFactory.class);
+            nameFactory = DefaultFactories.forBuildin(NameFactory.class, DefaultNameFactory.class);
         }
         this.nameFactory    = nameFactory;
-        this.typeFactory    = (nameFactory instanceof DefaultNameFactory) ? null : new TypeNames(nameFactory);
         this.namespace      = nameFactory.createNameSpace(nameFactory.createLocalName(parent, schemaName), null);
         this.description    = new WeakValueHashMap<TypeName,RecordType>(TypeName.class);
         this.attributeTypes = new ConcurrentHashMap<Class<?>,Type>();
@@ -187,7 +189,7 @@
             if (!e2.getKey().tip().toString().equals(e1.toString())) {
                 break;      // Member names differ.
             }
-            if (!((AttributeType) e2.getValue()).getValueClass().equals(e1.getValue())) {
+            if (!((SimpleAttributeType) e2.getValue()).getValueClass().equals(e1.getValue())) {
                 break;      // Value classes differ.
             }
         }
@@ -212,12 +214,7 @@
             if (valueClass == Void.TYPE) {
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "valueClass", "void"));
             }
-            final TypeName name;
-            if (nameFactory instanceof DefaultNameFactory) {
-                name = ((DefaultNameFactory) nameFactory).toTypeName(valueClass);
-            } else {
-                name = typeFactory.toTypeName(nameFactory, valueClass);
-            }
+            final TypeName name = nameFactory.toTypeName(valueClass);
             type = new SimpleAttributeType(name, valueClass);
             final Type old = attributeTypes.putIfAbsent(valueClass, type);
             if (old != null) {      // May happen if the type has been computed concurrently.
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
index 2a2cfe1..d41509a 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/DefaultRecordType.java
@@ -32,7 +32,6 @@
 import org.opengis.util.MemberName;
 import org.opengis.util.GenericName;
 import org.opengis.util.NameSpace;
-import org.opengis.util.NameFactory;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
 import org.opengis.util.RecordSchema;
@@ -193,7 +192,7 @@
      * @param nameFactory The factory to use for instantiating {@link MemberName}.
      */
     DefaultRecordType(final TypeName typeName, final RecordSchema container,
-            final Map<? extends CharSequence, ? extends Type> members, final NameFactory nameFactory)
+            final Map<? extends CharSequence, ? extends Type> members, final DefaultNameFactory nameFactory)
     {
         this.typeName  = typeName;
         this.container = container;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
index 653acde..828a543 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/RecordDefinition.java
@@ -26,7 +26,6 @@
 import org.opengis.util.Type;
 import org.opengis.util.RecordType;
 import org.opengis.util.MemberName;
-import org.opengis.feature.AttributeType;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Numbers;
@@ -36,6 +35,7 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.JDK7;
+import org.apache.sis.internal.simple.SimpleAttributeType;
 
 
 /**
@@ -156,8 +156,8 @@
         int i = 0;
         for (final Map.Entry<? extends MemberName, ? extends Type> entry : memberTypes.entrySet()) {
             final Type type = entry.getValue();
-            if (type instanceof AttributeType) {
-                final Class<?> c = ((AttributeType) type).getValueClass();
+            if (type instanceof SimpleAttributeType) {
+                final Class<?> c = ((SimpleAttributeType) type).getValueClass();
                 if (c != Object.class) {
                     if (valueClasses == null) {
                         valueClasses = new Class<?>[size];
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
index 66c9306..d1717a3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
@@ -31,7 +31,6 @@
 import org.opengis.annotation.UML;
 import org.opengis.util.CodeList;
 import org.opengis.util.InternationalString;
-import org.opengis.util.ControlledVocabulary;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Locales;
 import org.apache.sis.util.CharSequences;
@@ -51,14 +50,14 @@
  *
  * <ul>
  *   <li>Methods for fetching the ISO name or description of a code list:<ul>
- *     <li>{@link #getStandardName(Class)}            for ISO name</li>
- *     <li>{@link #getListName(ControlledVocabulary)} for ISO name</li>
- *     <li>{@link #getDescription(Class)}             for a description</li>
+ *     <li>{@link #getStandardName(Class)}   for ISO name</li>
+ *     <li>{@link #getListName(CodeList)}    for ISO name</li>
+ *     <li>{@link #getDescription(Class)}    for a description</li>
  *   </ul></li>
  *   <li>Methods for fetching the ISO name or description of a code value:<ul>
- *     <li>{@link #getCodeName(ControlledVocabulary)}    for ISO name,</li>
- *     <li>{@link #getCodeTitle(ControlledVocabulary)}   for a label or title</li>
- *     <li>{@link #getDescription(ControlledVocabulary)} for a more verbose description</li>
+ *     <li>{@link #getCodeName(CodeList)}    for ISO name,</li>
+ *     <li>{@link #getCodeTitle(CodeList)}   for a label or title</li>
+ *     <li>{@link #getDescription(CodeList)} for a more verbose description</li>
  *   </ul></li>
  *   <li>Methods for fetching an instance from a name (converse of above {@code get} methods):<ul>
  *     <li>{@link #forCodeName(Class, String, boolean)}</li>
@@ -88,7 +87,7 @@
  * Such substitution can be done with:
  *
  * <ul>
- *   <li>{@link #getCodeTitle(ControlledVocabulary)} for getting the {@link InternationalString} instance
+ *   <li>{@link #getCodeTitle(CodeList)} for getting the {@link InternationalString} instance
  *       to store in a metadata property.</li>
  *   <li>{@link #forCodeTitle(CharSequence)} for retrieving the {@link CodeList} previously stored as an
  *       {@code InternationalString}.</li>
@@ -179,11 +178,11 @@
      * @param  code The code for which to get the class name, or {@code null}.
      * @return The ISO (preferred) or Java (fallback) class name, or {@code null} if the given code is null.
      */
-    public static String getListName(final ControlledVocabulary code) {
+    public static String getListName(final CodeList<?> code) {
         if (code == null) {
             return null;
         }
-        final Class<?> type = (code instanceof Enum<?>) ? ((Enum<?>) code).getDeclaringClass() : code.getClass();
+        final Class<?> type = code.getClass();
         final String id = getStandardName(type);
         return (id != null) ? id : type.getSimpleName();
     }
@@ -205,12 +204,12 @@
      * @return The UML identifiers or programmatic name for the given code,
      *         or {@code null} if the given code is null.
      *
-     * @see #getCodeLabel(ControlledVocabulary)
-     * @see #getCodeTitle(ControlledVocabulary)
-     * @see #getDescription(ControlledVocabulary)
+     * @see #getCodeLabel(CodeList)
+     * @see #getCodeTitle(CodeList)
+     * @see #getDescription(CodeList)
      * @see #forCodeName(Class, String, boolean)
      */
-    public static String getCodeName(final ControlledVocabulary code) {
+    public static String getCodeName(final CodeList<?> code) {
         if (code == null) {
             return null;
         }
@@ -222,7 +221,7 @@
      * Returns a unlocalized title for the given enumeration or code list value.
      * This method builds a title using heuristics rules, which should give reasonable
      * results without the need of resource bundles. For better results, consider using
-     * {@link #getCodeTitle(ControlledVocabulary)} instead.
+     * {@link #getCodeTitle(CodeList)} instead.
      *
      * <p>The current heuristic implementation iterates over {@linkplain CodeList#names() all code names},
      * selects the longest one excluding the {@linkplain CodeList#name() field name} if possible, then
@@ -239,11 +238,11 @@
      * @param  code The code from which to get a title, or {@code null}.
      * @return A unlocalized title for the given code, or {@code null} if the given code is null.
      *
-     * @see #getCodeName(ControlledVocabulary)
-     * @see #getCodeTitle(ControlledVocabulary)
-     * @see #getDescription(ControlledVocabulary)
+     * @see #getCodeName(CodeList)
+     * @see #getCodeTitle(CodeList)
+     * @see #getDescription(CodeList)
      */
-    public static String getCodeLabel(final ControlledVocabulary code) {
+    public static String getCodeLabel(final CodeList<?> code) {
         if (code == null) {
             return null;
         }
@@ -262,7 +261,7 @@
 
     /**
      * Returns the title of the given enumeration or code list value. Title are usually much shorter than descriptions.
-     * English titles are often the same than the {@linkplain #getCodeLabel(ControlledVocabulary) code labels}.
+     * English titles are often the same than the {@linkplain #getCodeLabel(CodeList) code labels}.
      *
      * <p>The code or enumeration value given in argument to this method can be retrieved from the returned title
      * with the {@link #forCodeTitle(CharSequence)} method. See <cite>Substituting a free text by a code list</cite>
@@ -271,10 +270,10 @@
      * @param  code The code for which to get the title, or {@code null}.
      * @return The title, or {@code null} if the given code is null.
      *
-     * @see #getDescription(ControlledVocabulary)
+     * @see #getDescription(CodeList)
      * @see #forCodeTitle(CharSequence)
      */
-    public static InternationalString getCodeTitle(final ControlledVocabulary code) {
+    public static InternationalString getCodeTitle(final CodeList<?> code) {
         return (code != null) ? new CodeTitle(code) : null;
     }
 
@@ -286,10 +285,10 @@
      * @param  code The code for which to get the localized description, or {@code null}.
      * @return The description, or {@code null} if none or if the given code is null.
      *
-     * @see #getCodeTitle(ControlledVocabulary)
+     * @see #getCodeTitle(CodeList)
      * @see #getDescription(Class)
      */
-    public static InternationalString getDescription(final ControlledVocabulary code) {
+    public static InternationalString getDescription(final CodeList<?> code) {
         if (code != null) {
             final String resources = getResources(code.getClass().getName());
             if (resources != null) {
@@ -306,7 +305,7 @@
      * @param  type The GeoAPI interface or code list from which to get the description, or {@code null}.
      * @return The description, or {@code null} if none or if the given type is {@code null}.
      *
-     * @see #getDescription(ControlledVocabulary)
+     * @see #getDescription(CodeList)
      */
     public static InternationalString getDescription(final Class<?> type) {
         final String name = getStandardName(type);
@@ -405,7 +404,7 @@
         /**
          * Returns the resource key for the given code list.
          */
-        static String resourceKey(final ControlledVocabulary code) {
+        static String resourceKey(final CodeList<?> code) {
             String key = getCodeName(code);
             if (key.indexOf(SEPARATOR) < 0) {
                 key = getListName(code) + SEPARATOR + key;
@@ -435,14 +434,14 @@
         /**
          * The code list for which to create a title.
          */
-        final ControlledVocabulary code;
+        final CodeList<?> code;
 
         /**
          * Creates a new international string for the given code list element.
          *
          * @param code The code list for which to create a title.
          */
-        CodeTitle(final ControlledVocabulary code) {
+        CodeTitle(final CodeList<?> code) {
             super("org.opengis.metadata.CodeLists", resourceKey(code));
             this.code = code;
         }
@@ -472,22 +471,18 @@
     }
 
     /**
-     * Returns all known values for the given type of code list or enumeration.
+     * Returns all known values for the given type of code list.
      * Note that the size of the returned array may growth between different invocations of this method,
      * since users can add their own codes to an existing list.
      *
-     * <div class="note"><b>Note:</b>
-     * This method works with both {@link Enum} and {@link CodeList}. However if the type is known to be an
-     * {@code Enum}, then the standard {@link Class#getEnumConstants()} method is more efficient.</div>
-     *
      * @param <T> The compile-time type given as the {@code codeType} parameter.
-     * @param codeType The type of code list or enumeration.
-     * @return The list of values for the given code list or enumeration, or an empty array if none.
+     * @param codeType The type of code list.
+     * @return The list of values for the given code list, or an empty array if none.
      *
      * @see Class#getEnumConstants()
      */
     @SuppressWarnings("unchecked")
-    public static <T extends ControlledVocabulary> T[] getCodeValues(final Class<T> codeType) {
+    public static <T extends CodeList<?>> T[] getCodeValues(final Class<T> codeType) {
         Object values;
         try {
             values = codeType.getMethod("values", (Class<?>[]) null).invoke(null, (Object[]) null);
@@ -531,7 +526,7 @@
             return null;
         }
         if (typeForNames == null) {
-            final Class<UML> c = UML.class;
+            final Class<?> c = Types.class;
             final InputStream in = c.getResourceAsStream("class-index.properties");
             if (in == null) {
                 throw new MissingResourceException("class-index.properties", c.getName(), identifier);
@@ -595,19 +590,9 @@
             if (values == null) {
                 throw e;
             }
-            if (values instanceof ControlledVocabulary[]) {
-                for (final ControlledVocabulary code : (ControlledVocabulary[]) values) {
-                    for (final String candidate : code.names()) {
-                        if (CodeListFilter.accept(candidate, name)) {
-                            return enumType.cast(code);
-                        }
-                    }
-                }
-            } else {
-                for (final Enum<?> code : values) {
-                    if (CodeListFilter.accept(code.name(), name)) {
-                        return enumType.cast(code);
-                    }
+            for (final Enum<?> code : values) {
+                if (CodeListFilter.accept(code.name(), name)) {
+                    return enumType.cast(code);
                 }
             }
         }
@@ -635,7 +620,7 @@
      * @return A code matching the given name, or {@code null} if the name is null
      *         or if no matching code is found and {@code canCreate} is {@code false}.
      *
-     * @see #getCodeName(ControlledVocabulary)
+     * @see #getCodeName(CodeList)
      * @see CodeList#valueOf(Class, String)
      */
     public static <T extends CodeList<T>> T forCodeName(final Class<T> codeType, String name, final boolean canCreate) {
@@ -643,6 +628,16 @@
         if (name == null || name.isEmpty()) {
             return null;
         }
+        // -------- Begin workaround for GeoAPI 3.0 (TODO: remove after upgrade to GeoAPI 3.1) ------------
+        final String typeName = codeType.getName();
+        try {
+            // Forces initialization of the given class in order
+            // to register its list of static final constants.
+            Class.forName(typeName, true, codeType.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new TypeNotPresentException(typeName, e); // Should never happen.
+        }
+        // -------- End workaround ------------------------------------------------------------------------
         return CodeList.valueOf(codeType, new CodeListFilter(name, canCreate));
     }
 
@@ -651,7 +646,7 @@
      * The current implementation performs the following choice:
      *
      * <ul>
-     *   <li>If the given title is a value returned by a previous call to {@link #getCodeTitle(ControlledVocabulary)},
+     *   <li>If the given title is a value returned by a previous call to {@link #getCodeTitle(CodeList)},
      *       returns the code or enumeration value used for creating that title.</li>
      *   <li>Otherwise returns {@code null}.</li>
      * </ul>
@@ -661,9 +656,9 @@
      *
      * @since 0.7
      *
-     * @see #getCodeTitle(ControlledVocabulary)
+     * @see #getCodeTitle(CodeList)
      */
-    public static ControlledVocabulary forCodeTitle(final CharSequence title) {
+    public static CodeList<?> forCodeTitle(final CharSequence title) {
         return (title instanceof CodeTitle) ? ((CodeTitle) title).code : null;
     }
 
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java b/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
index e3594ca..283d2f6 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/iso/package-info.java
@@ -26,7 +26,7 @@
  *       <li>{@link org.apache.sis.util.iso.SimpleInternationalString}   for wrapping a single {@link java.lang.String};</li>
  *       <li>{@link org.apache.sis.util.iso.DefaultInternationalString}  for providing many localizations in a {@link java.util.Map};</li>
  *       <li>{@link org.apache.sis.util.iso.ResourceInternationalString} for providing localizations from a {@link java.util.ResourceBundle}.</li>
- *       <li>{@link org.apache.sis.util.iso.Types#getCodeTitle Types.getCodeTitle(ControlledVocabulary)} for wrapping a {@link org.opengis.util.CodeList} value.</li>
+ *       <li>{@link org.apache.sis.util.iso.Types#getCodeTitle Types.getCodeTitle(CodeList)} for wrapping a {@link org.opengis.util.CodeList} value.</li>
  *     </ul>
  *   </li>
  *   <li>Implementations of {@link org.opengis.util.GenericName} (derived from ISO 19103):
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java b/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
index be15119..23d2019 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
@@ -32,7 +32,6 @@
 import java.lang.reflect.Modifier;
 import javax.measure.unit.Unit;
 import org.opengis.util.CodeList;
-import org.opengis.util.ControlledVocabulary;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
@@ -415,8 +414,8 @@
                 replacement = message;
             } else if (element instanceof Class<?>) {
                 replacement = Classes.getShortName(getPublicType((Class<?>) element));
-            } else if (element instanceof ControlledVocabulary) {
-                replacement = Types.getCodeTitle((ControlledVocabulary) element).toString(getLocale());
+            } else if (element instanceof CodeList<?>) {
+                replacement = Types.getCodeTitle((CodeList<?>) element).toString(getLocale());
             } else if (element instanceof Unit<?>) {
                 replacement = PatchedUnitFormat.toString((Unit<?>) element);
             }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/xml/LegacyCodes.java b/core/sis-utility/src/main/java/org/apache/sis/xml/LegacyCodes.java
index 5cfccbc..713a0d3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/xml/LegacyCodes.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/xml/LegacyCodes.java
@@ -19,13 +19,8 @@
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Locale;
-import java.util.Properties;
-import java.io.InputStream;
-import java.io.IOException;
-import org.opengis.metadata.Metadata;
-import org.apache.sis.internal.system.Loggers;
+import org.opengis.metadata.identification.CharacterSet;
 import org.apache.sis.util.collection.Containers;
-import org.apache.sis.util.logging.Logging;
 
 
 /**
@@ -50,20 +45,15 @@
      */
     static final Map<String,String> IANA_TO_LEGACY, LEGACY_TO_IANA;
     static {
-        final Properties codes = new Properties();
-        final InputStream in = Metadata.class.getResourceAsStream("2003/charset-codes.properties");
-        try {
-            codes.load(in);
-            in.close();
-        } catch (IOException e) {
-            Logging.unexpectedException(Logging.getLogger(Loggers.XML), ValueConverter.class, "toCharset[Code]", e);
-        }
-        final int capacity = Containers.hashMapCapacity(codes.size());
+        final CharacterSet[] codes = CharacterSet.values();
+        final int capacity = Containers.hashMapCapacity(codes.length);
         IANA_TO_LEGACY = new HashMap<String,String>(capacity);
         LEGACY_TO_IANA = new HashMap<String,String>(capacity);
-        for (final Map.Entry<Object,Object> entry : codes.entrySet()) {
-            final String legacy = ((String) entry.getKey()).intern();
-            final String name   = ((String) entry.getValue()).intern();
+        for (final CharacterSet code : codes) {
+            final String   legacy = code.identifier().intern();
+            final String[] names  = code.names();
+            String name = names[names.length - 1];
+            if (name.equals("ebcdic")) name = "EBCDIC"; // Missing IANA name in GeoAPI CharacterSet.
             IANA_TO_LEGACY.put(name  .toUpperCase(Locale.US), legacy); // IANA names are restricted to US-ASCII.
             LEGACY_TO_IANA.put(legacy.toLowerCase(Locale.US), name);
             IANA_TO_LEGACY.put(name, legacy);
diff --git a/core/sis-utility/src/main/resources/org/apache/sis/util/iso/class-index.properties b/core/sis-utility/src/main/resources/org/apache/sis/util/iso/class-index.properties
new file mode 100644
index 0000000..ee24498
--- /dev/null
+++ b/core/sis-utility/src/main/resources/org/apache/sis/util/iso/class-index.properties
@@ -0,0 +1,211 @@
+#
+# This is an automatically generated file. The same content is provided by GeoAPI 3.1
+# in the org.opengis.annotation package. Since this file does not exist in GeoAPI 3.0,
+# the Apache SIS branch for GeoAPI 3.0 maintains this copy (provided by the original
+# author).
+#
+CC_ConcatenatedOperation=org.opengis.referencing.operation.ConcatenatedOperation
+CC_Conversion=org.opengis.referencing.operation.Conversion
+CC_CoordinateOperation=org.opengis.referencing.operation.CoordinateOperation
+CC_Formula=org.opengis.referencing.operation.Formula
+CC_GeneralOperationParameter=org.opengis.parameter.GeneralParameterDescriptor
+CC_GeneralParameterValue=org.opengis.parameter.GeneralParameterValue
+CC_OperationMethod=org.opengis.referencing.operation.OperationMethod
+CC_OperationParameter=org.opengis.parameter.ParameterDescriptor
+CC_OperationParameterGroup=org.opengis.parameter.ParameterDescriptorGroup
+CC_ParameterValue=org.opengis.parameter.ParameterValue
+CC_ParameterValueGroup=org.opengis.parameter.ParameterValueGroup
+CC_PassThroughOperation=org.opengis.referencing.operation.PassThroughOperation
+CC_SingleOperation=org.opengis.referencing.operation.SingleOperation
+CC_Transformation=org.opengis.referencing.operation.Transformation
+CD_Datum=org.opengis.referencing.datum.Datum
+CD_Ellipsoid=org.opengis.referencing.datum.Ellipsoid
+CD_EngineeringDatum=org.opengis.referencing.datum.EngineeringDatum
+CD_GeodeticDatum=org.opengis.referencing.datum.GeodeticDatum
+CD_ImageDatum=org.opengis.referencing.datum.ImageDatum
+CD_PixelInCell=org.opengis.referencing.datum.PixelInCell
+CD_PrimeMeridian=org.opengis.referencing.datum.PrimeMeridian
+CD_TemporalDatum=org.opengis.referencing.datum.TemporalDatum
+CD_VerticalDatum=org.opengis.referencing.datum.VerticalDatum
+CD_VerticalDatumType=org.opengis.referencing.datum.VerticalDatumType
+CI_Address=org.opengis.metadata.citation.Address
+CI_Citation=org.opengis.metadata.citation.Citation
+CI_Contact=org.opengis.metadata.citation.Contact
+CI_Date=org.opengis.metadata.citation.CitationDate
+CI_DateTypeCode=org.opengis.metadata.citation.DateType
+CI_OnLineFunctionCode=org.opengis.metadata.citation.OnLineFunction
+CI_OnlineResource=org.opengis.metadata.citation.OnlineResource
+CI_PresentationFormCode=org.opengis.metadata.citation.PresentationForm
+CI_ResponsibleParty=org.opengis.metadata.citation.ResponsibleParty
+CI_RoleCode=org.opengis.metadata.citation.Role
+CI_Series=org.opengis.metadata.citation.Series
+CI_Telephone=org.opengis.metadata.citation.Telephone
+CS_AffineCS=org.opengis.referencing.cs.AffineCS
+CS_AxisDirection=org.opengis.referencing.cs.AxisDirection
+CS_CartesianCS=org.opengis.referencing.cs.CartesianCS
+CS_CoordinateSystem=org.opengis.referencing.cs.CoordinateSystem
+CS_CoordinateSystemAxis=org.opengis.referencing.cs.CoordinateSystemAxis
+CS_CylindricalCS=org.opengis.referencing.cs.CylindricalCS
+CS_EllipsoidalCS=org.opengis.referencing.cs.EllipsoidalCS
+CS_LinearCS=org.opengis.referencing.cs.LinearCS
+CS_PolarCS=org.opengis.referencing.cs.PolarCS
+CS_RangeMeaning=org.opengis.referencing.cs.RangeMeaning
+CS_SphericalCS=org.opengis.referencing.cs.SphericalCS
+CS_TimeCS=org.opengis.referencing.cs.TimeCS
+CS_UserDefinedCS=org.opengis.referencing.cs.UserDefinedCS
+CS_VerticalCS=org.opengis.referencing.cs.VerticalCS
+DQ_AbsoluteExternalPositionalAccuracy=org.opengis.metadata.quality.AbsoluteExternalPositionalAccuracy
+DQ_AccuracyOfATimeMeasurement=org.opengis.metadata.quality.AccuracyOfATimeMeasurement
+DQ_Completeness=org.opengis.metadata.quality.Completeness
+DQ_CompletenessCommission=org.opengis.metadata.quality.CompletenessCommission
+DQ_CompletenessOmission=org.opengis.metadata.quality.CompletenessOmission
+DQ_ConceptualConsistency=org.opengis.metadata.quality.ConceptualConsistency
+DQ_ConformanceResult=org.opengis.metadata.quality.ConformanceResult
+DQ_DataQuality=org.opengis.metadata.quality.DataQuality
+DQ_DomainConsistency=org.opengis.metadata.quality.DomainConsistency
+DQ_Element=org.opengis.metadata.quality.Element
+DQ_EvaluationMethodTypeCode=org.opengis.metadata.quality.EvaluationMethodType
+DQ_FormatConsistency=org.opengis.metadata.quality.FormatConsistency
+DQ_GriddedDataPositionalAccuracy=org.opengis.metadata.quality.GriddedDataPositionalAccuracy
+DQ_LogicalConsistency=org.opengis.metadata.quality.LogicalConsistency
+DQ_NonQuantitativeAttributeAccuracy=org.opengis.metadata.quality.NonQuantitativeAttributeAccuracy
+DQ_PositionalAccuracy=org.opengis.metadata.quality.PositionalAccuracy
+DQ_QuantitativeAttributeAccuracy=org.opengis.metadata.quality.QuantitativeAttributeAccuracy
+DQ_QuantitativeResult=org.opengis.metadata.quality.QuantitativeResult
+DQ_RelativeInternalPositionalAccuracy=org.opengis.metadata.quality.RelativeInternalPositionalAccuracy
+DQ_Result=org.opengis.metadata.quality.Result
+DQ_Scope=org.opengis.metadata.quality.Scope
+DQ_TemporalAccuracy=org.opengis.metadata.quality.TemporalAccuracy
+DQ_TemporalConsistency=org.opengis.metadata.quality.TemporalConsistency
+DQ_TemporalValidity=org.opengis.metadata.quality.TemporalValidity
+DQ_ThematicAccuracy=org.opengis.metadata.quality.ThematicAccuracy
+DQ_ThematicClassificationCorrectness=org.opengis.metadata.quality.ThematicClassificationCorrectness
+DQ_TopologicalConsistency=org.opengis.metadata.quality.TopologicalConsistency
+DS_AssociationTypeCode=org.opengis.metadata.identification.AssociationType
+DS_InitiativeTypeCode=org.opengis.metadata.identification.InitiativeType
+EX_BoundingPolygon=org.opengis.metadata.extent.BoundingPolygon
+EX_Extent=org.opengis.metadata.extent.Extent
+EX_GeographicBoundingBox=org.opengis.metadata.extent.GeographicBoundingBox
+EX_GeographicDescription=org.opengis.metadata.extent.GeographicDescription
+EX_GeographicExtent=org.opengis.metadata.extent.GeographicExtent
+EX_SpatialTemporalExtent=org.opengis.metadata.extent.SpatialTemporalExtent
+EX_TemporalExtent=org.opengis.metadata.extent.TemporalExtent
+EX_VerticalExtent=org.opengis.metadata.extent.VerticalExtent
+IO_IdentifiedObject=org.opengis.referencing.IdentifiedObject
+LE_Algorithm=org.opengis.metadata.lineage.Algorithm
+LE_NominalResolution=org.opengis.metadata.lineage.NominalResolution
+LE_ProcessStep=org.opengis.metadata.lineage.ProcessStep
+LE_ProcessStepReport=org.opengis.metadata.lineage.ProcessStepReport
+LE_Processing=org.opengis.metadata.lineage.Processing
+LE_Source=org.opengis.metadata.lineage.Source
+LI_Lineage=org.opengis.metadata.lineage.Lineage
+LI_ProcessStep=org.opengis.metadata.lineage.ProcessStep
+LI_Source=org.opengis.metadata.lineage.Source
+MD_AggregateInformation=org.opengis.metadata.identification.AggregateInformation
+MD_ApplicationSchemaInformation=org.opengis.metadata.ApplicationSchemaInformation
+MD_Band=org.opengis.metadata.content.Band
+MD_BrowseGraphic=org.opengis.metadata.identification.BrowseGraphic
+MD_CellGeometryCode=org.opengis.metadata.spatial.CellGeometry
+MD_CharacterSetCode=org.opengis.metadata.identification.CharacterSet
+MD_ClassificationCode=org.opengis.metadata.constraint.Classification
+MD_Constraints=org.opengis.metadata.constraint.Constraints
+MD_ContentInformation=org.opengis.metadata.content.ContentInformation
+MD_CoverageContentTypeCode=org.opengis.metadata.content.CoverageContentType
+MD_CoverageDescription=org.opengis.metadata.content.CoverageDescription
+MD_DataIdentification=org.opengis.metadata.identification.DataIdentification
+MD_DatatypeCode=org.opengis.metadata.Datatype
+MD_DigitalTransferOptions=org.opengis.metadata.distribution.DigitalTransferOptions
+MD_Dimension=org.opengis.metadata.spatial.Dimension
+MD_DimensionNameTypeCode=org.opengis.metadata.spatial.DimensionNameType
+MD_Distribution=org.opengis.metadata.distribution.Distribution
+MD_Distributor=org.opengis.metadata.distribution.Distributor
+MD_ExtendedElementInformation=org.opengis.metadata.ExtendedElementInformation
+MD_FeatureCatalogueDescription=org.opengis.metadata.content.FeatureCatalogueDescription
+MD_FeatureTypeList=org.opengis.metadata.FeatureTypeList
+MD_Format=org.opengis.metadata.distribution.Format
+MD_GeometricObjectTypeCode=org.opengis.metadata.spatial.GeometricObjectType
+MD_GeometricObjects=org.opengis.metadata.spatial.GeometricObjects
+MD_Georectified=org.opengis.metadata.spatial.Georectified
+MD_Georeferenceable=org.opengis.metadata.spatial.Georeferenceable
+MD_GridSpatialRepresentation=org.opengis.metadata.spatial.GridSpatialRepresentation
+MD_Identification=org.opengis.metadata.identification.Identification
+MD_Identifier=org.opengis.metadata.Identifier
+MD_ImageDescription=org.opengis.metadata.content.ImageDescription
+MD_ImagingConditionCode=org.opengis.metadata.content.ImagingCondition
+MD_KeywordTypeCode=org.opengis.metadata.identification.KeywordType
+MD_Keywords=org.opengis.metadata.identification.Keywords
+MD_LegalConstraints=org.opengis.metadata.constraint.LegalConstraints
+MD_MaintenanceFrequencyCode=org.opengis.metadata.maintenance.MaintenanceFrequency
+MD_MaintenanceInformation=org.opengis.metadata.maintenance.MaintenanceInformation
+MD_Medium=org.opengis.metadata.distribution.Medium
+MD_MediumFormatCode=org.opengis.metadata.distribution.MediumFormat
+MD_MediumNameCode=org.opengis.metadata.distribution.MediumName
+MD_Metadata=org.opengis.metadata.Metadata
+MD_MetadataExtensionInformation=org.opengis.metadata.MetadataExtensionInformation
+MD_ObligationCode=org.opengis.metadata.Obligation
+MD_PixelOrientationCode=org.opengis.metadata.spatial.PixelOrientation
+MD_PortrayalCatalogueReference=org.opengis.metadata.PortrayalCatalogueReference
+MD_ProgressCode=org.opengis.metadata.identification.Progress
+MD_RangeDimension=org.opengis.metadata.content.RangeDimension
+MD_RepresentativeFraction=org.opengis.metadata.identification.RepresentativeFraction
+MD_Resolution=org.opengis.metadata.identification.Resolution
+MD_RestrictionCode=org.opengis.metadata.constraint.Restriction
+MD_ScopeCode=org.opengis.metadata.maintenance.ScopeCode
+MD_ScopeDescription=org.opengis.metadata.maintenance.ScopeDescription
+MD_SecurityConstraints=org.opengis.metadata.constraint.SecurityConstraints
+MD_SpatialRepresentation=org.opengis.metadata.spatial.SpatialRepresentation
+MD_SpatialRepresentationTypeCode=org.opengis.metadata.spatial.SpatialRepresentationType
+MD_StandardOrderProcess=org.opengis.metadata.distribution.StandardOrderProcess
+MD_TopicCategoryCode=org.opengis.metadata.identification.TopicCategory
+MD_TopologyLevelCode=org.opengis.metadata.spatial.TopologyLevel
+MD_Usage=org.opengis.metadata.identification.Usage
+MD_VectorSpatialRepresentation=org.opengis.metadata.spatial.VectorSpatialRepresentation
+MI_AcquisitionInformation=org.opengis.metadata.acquisition.AcquisitionInformation
+MI_Band=org.opengis.metadata.content.Band
+MI_BandDefinition=org.opengis.metadata.content.BandDefinition
+MI_ContextCode=org.opengis.metadata.acquisition.Context
+MI_CoverageDescription=org.opengis.metadata.content.CoverageDescription
+MI_EnvironmentalRecord=org.opengis.metadata.acquisition.EnvironmentalRecord
+MI_Event=org.opengis.metadata.acquisition.Event
+MI_GCP=org.opengis.metadata.spatial.GCP
+MI_GCPCollection=org.opengis.metadata.spatial.GCPCollection
+MI_GeolocationInformation=org.opengis.metadata.spatial.GeolocationInformation
+MI_GeometryTypeCode=org.opengis.metadata.acquisition.GeometryType
+MI_Georectified=org.opengis.metadata.spatial.Georectified
+MI_Georeferenceable=org.opengis.metadata.spatial.Georeferenceable
+MI_ImageDescription=org.opengis.metadata.content.ImageDescription
+MI_Instrument=org.opengis.metadata.acquisition.Instrument
+MI_Metadata=org.opengis.metadata.Metadata
+MI_Objective=org.opengis.metadata.acquisition.Objective
+MI_ObjectiveTypeCode=org.opengis.metadata.acquisition.ObjectiveType
+MI_Operation=org.opengis.metadata.acquisition.Operation
+MI_OperationTypeCode=org.opengis.metadata.acquisition.OperationType
+MI_Plan=org.opengis.metadata.acquisition.Plan
+MI_Platform=org.opengis.metadata.acquisition.Platform
+MI_PlatformPass=org.opengis.metadata.acquisition.PlatformPass
+MI_PolarizationOrientationCode=org.opengis.metadata.content.PolarizationOrientation
+MI_PriorityCode=org.opengis.metadata.acquisition.Priority
+MI_RangeElementDescription=org.opengis.metadata.content.RangeElementDescription
+MI_RequestedDate=org.opengis.metadata.acquisition.RequestedDate
+MI_Requirement=org.opengis.metadata.acquisition.Requirement
+MI_SequenceCode=org.opengis.metadata.acquisition.Sequence
+MI_TransferFunctionTypeCode=org.opengis.metadata.content.TransferFunctionType
+MI_TriggerCode=org.opengis.metadata.acquisition.Trigger
+QE_CoverageResult=org.opengis.metadata.quality.CoverageResult
+QE_Usability=org.opengis.metadata.quality.Usability
+RS_Identifier=org.opengis.referencing.ReferenceIdentifier
+RS_ReferenceSystem=org.opengis.referencing.ReferenceSystem
+SC_CRS=org.opengis.referencing.crs.CoordinateReferenceSystem
+SC_CompoundCRS=org.opengis.referencing.crs.CompoundCRS
+SC_DerivedCRS=org.opengis.referencing.crs.DerivedCRS
+SC_EngineeringCRS=org.opengis.referencing.crs.EngineeringCRS
+SC_GeneralDerivedCRS=org.opengis.referencing.crs.GeneralDerivedCRS
+SC_GeocentricCRS=org.opengis.referencing.crs.GeocentricCRS
+SC_GeodeticCRS=org.opengis.referencing.crs.GeodeticCRS
+SC_GeographicCRS=org.opengis.referencing.crs.GeographicCRS
+SC_ImageCRS=org.opengis.referencing.crs.ImageCRS
+SC_ProjectedCRS=org.opengis.referencing.crs.ProjectedCRS
+SC_SingleCRS=org.opengis.referencing.crs.SingleCRS
+SC_TemporalCRS=org.opengis.referencing.crs.TemporalCRS
+SC_VerticalCRS=org.opengis.referencing.crs.VerticalCRS
+SV_ServiceIdentification=org.opengis.metadata.identification.ServiceIdentification
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/EnumAdapterTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/EnumAdapterTest.java
deleted file mode 100644
index b0cea40..0000000
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/EnumAdapterTest.java
+++ /dev/null
@@ -1,44 +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.jaxb.gmd;
-
-import org.apache.sis.test.XMLTestCase;
-import org.junit.Test;
-
-import static org.apache.sis.test.Assert.*;
-
-
-/**
- * Tests the {@link EnumAdapter} class.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
- * @version 0.6
- * @module
- */
-public final strictfp class EnumAdapterTest extends XMLTestCase {
-    /**
-     * Tests the {@link EnumAdapter#name(String)} method.
-     */
-    @Test
-    public void testEnumAdapterName() {
-        assertEquals("IN_OUT",                        EnumAdapter.name("in/out"));
-        assertEquals("OCEANS",                        EnumAdapter.name("oceans"));
-        assertEquals("ENVIRONMENT",                   EnumAdapter.name("environment"));
-        assertEquals("IMAGERY_BASE_MAPS_EARTH_COVER", EnumAdapter.name("imageryBaseMapsEarthCover"));
-    }
-}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/LanguageCodeTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/LanguageCodeTest.java
index 6b9037a..7528ad3 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/LanguageCodeTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gmd/LanguageCodeTest.java
@@ -36,7 +36,6 @@
 import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
-import static org.apache.sis.test.TestUtilities.getSingleton;
 
 
 /**
@@ -156,7 +155,7 @@
         final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
         final String xml = getMetadataXML(LANGUAGE_CODE);
         final Metadata metadata = (Metadata) unmarshal(unmarshaller, xml);
-        assertEquals(Locale.JAPANESE, getSingleton(metadata.getLanguages()));
+        assertEquals(Locale.JAPANESE, metadata.getLanguage());
     }
 
     /**
@@ -179,7 +178,7 @@
         final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
         final String xml = getMetadataXML(LANGUAGE_CODE_WITHOUT_ATTRIBUTE);
         final Metadata metadata = (Metadata) unmarshal(unmarshaller, xml);
-        assertEquals(Locale.JAPANESE, getSingleton(metadata.getLanguages()));
+        assertEquals(Locale.JAPANESE, metadata.getLanguage());
         pool.recycle(unmarshaller);
     }
 
@@ -220,7 +219,7 @@
         final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
         final String xml = getMetadataXML(CHARACTER_STRING);
         final Metadata metadata = (Metadata) unmarshal(unmarshaller, xml);
-        assertEquals(Locale.JAPANESE, getSingleton(metadata.getLanguages()));
+        assertEquals(Locale.JAPANESE, metadata.getLanguage());
         pool.recycle(unmarshaller);
     }
 }
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/DummyInstant.java b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/DummyInstant.java
deleted file mode 100644
index 913ab07..0000000
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/DummyInstant.java
+++ /dev/null
@@ -1,67 +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.jaxb.gml;
-
-import java.util.Date;
-import org.opengis.temporal.Instant;
-import org.opengis.temporal.Duration;
-import org.opengis.temporal.RelativePosition;
-import org.opengis.temporal.TemporalPosition;
-import org.opengis.temporal.TemporalPrimitive;
-import org.opengis.temporal.TemporalGeometricPrimitive;
-import org.apache.sis.internal.simple.SimpleIdentifiedObject;
-
-
-/**
- * A dummy {@link Instant} implementation, for testing the JAXB elements without dependency
- * toward the {@code sis-temporal} module.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.3
- * @version 0.5
- * @module
- */
-@SuppressWarnings("serial")
-final class DummyInstant extends SimpleIdentifiedObject implements Instant {
-    /**
-     * The time, in milliseconds elapsed since January 1st, 1970.
-     */
-    private final long time;
-
-    /**
-     * Creates a new instant initialized to the given value.
-     */
-    DummyInstant(final Date time) {
-        this.time = time.getTime();
-    }
-
-    /**
-     * Returns the date of this instant object.
-     */
-    @Override
-    public Date getDate() {
-        return new Date(time);
-    }
-
-    /**
-     * Unsupported operations.
-     */
-    @Override public Duration         length()                                   {throw new UnsupportedOperationException();}
-    @Override public RelativePosition relativePosition(TemporalPrimitive  other) {throw new UnsupportedOperationException();}
-    @Override public Duration         distance(TemporalGeometricPrimitive other) {throw new UnsupportedOperationException();}
-    @Override public TemporalPosition getTemporalPosition()                      {throw new UnsupportedOperationException();}
-}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/TimePeriodTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/TimePeriodTest.java
index ef4c31e..b692f3b 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/TimePeriodTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/jaxb/gml/TimePeriodTest.java
@@ -111,128 +111,4 @@
         pool.recycle(marshaller);
         pool.recycle(unmarshaller);
     }
-
-    /**
-     * Tests a time period using the GML 2 syntax.
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @throws JAXBException If an error occurred while marshalling.
-     */
-    @Test
-    public void testPeriodGML2() throws JAXBException {
-        createContext();
-        final TimePeriodBound begin = new TimePeriodBound.GML2(new DummyInstant(date("1992-01-01 00:00:00")));
-        final TimePeriodBound end   = new TimePeriodBound.GML2(new DummyInstant(date("2007-12-31 00:00:00")));
-        testPeriod(begin, end,
-                "<gml:TimePeriod xmlns:gml=\"" + Namespaces.GML + "\">\n" +
-                "  <gml:begin>\n" +
-                "    <gml:TimeInstant>\n" +
-                "      <gml:timePosition>1992-01-01T01:00:00+01:00</gml:timePosition>\n" +
-                "    </gml:TimeInstant>\n" +
-                "  </gml:begin>\n" +
-                "  <gml:end>\n" +
-                "    <gml:TimeInstant>\n" +
-                "      <gml:timePosition>2007-12-31T01:00:00+01:00</gml:timePosition>\n" +
-                "    </gml:TimeInstant>\n" +
-                "  </gml:end>\n" +
-                "</gml:TimePeriod>\n", true);
-    }
-
-    /**
-     * Tests a time period using GML2 or GML3 syntax. This method is used for the
-     * implementation of {@link #testPeriodGML2()} and {@link #testPeriodGML3()}.
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @param expected The expected string.
-     */
-    private void testPeriod(final TimePeriodBound begin, final TimePeriodBound end,
-            final String expected, final boolean verifyValues) throws JAXBException
-    {
-        final Marshaller   marshaller   = pool.acquireMarshaller();
-        final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
-        final TimePeriod   period       = new TimePeriod();
-        period.begin = begin;
-        period.end   = end;
-        final String actual = marshal(marshaller, period);
-        assertXmlEquals(expected, actual, "xmlns:*");
-        final TimePeriod test = (TimePeriod) unmarshal(unmarshaller, actual);
-        if (verifyValues) {
-            assertEquals("1992-01-01 00:00:00", format(XmlUtilities.toDate(context, test.begin.calendar())));
-            assertEquals("2007-12-31 00:00:00", format(XmlUtilities.toDate(context, test.end  .calendar())));
-        }
-        pool.recycle(marshaller);
-        pool.recycle(unmarshaller);
-    }
-
-    /**
-     * Tests a time period using the GML 3 syntax.
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @throws JAXBException If an error occurred while marshalling.
-     */
-    @Test
-    public void testPeriodGML3() throws JAXBException {
-        createContext();
-        final TimePeriodBound begin = new TimePeriodBound.GML3(new DummyInstant(date("1992-01-01 00:00:00")), "before");
-        final TimePeriodBound end   = new TimePeriodBound.GML3(new DummyInstant(date("2007-12-31 00:00:00")), "after");
-        testPeriod(begin, end,
-                "<gml:TimePeriod xmlns:gml=\"" + Namespaces.GML + "\">\n" +
-                "  <gml:beginPosition>1992-01-01T01:00:00+01:00</gml:beginPosition>\n" +
-                "  <gml:endPosition>2007-12-31T01:00:00+01:00</gml:endPosition>\n" +
-                "</gml:TimePeriod>\n", true);
-    }
-
-    /**
-     * Same test than {@link #testPeriodGML3()}, but with simplified date format (omit the hours and timezone)
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @throws JAXBException If an error occurred while marshalling.
-     */
-    @Test
-    public void testSimplifiedPeriodGML3() throws JAXBException {
-        createContext();
-        final TimePeriodBound begin = new TimePeriodBound.GML3(new DummyInstant(date("1992-01-01 23:00:00")), "before");
-        final TimePeriodBound end   = new TimePeriodBound.GML3(new DummyInstant(date("2007-12-30 23:00:00")), "after");
-        testPeriod(begin, end,
-                "<gml:TimePeriod xmlns:gml=\"" + Namespaces.GML + "\">\n" +
-                "  <gml:beginPosition>1992-01-02</gml:beginPosition>\n" +
-                "  <gml:endPosition>2007-12-31</gml:endPosition>\n" +
-                "</gml:TimePeriod>\n", false);
-    }
-
-    /**
-     * Same test than {@link #testSimplifiedPeriodGML3()}, but without beginning boundary.
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @throws JAXBException If an error occurred while marshalling.
-     */
-    @Test
-    public void testBeforePeriodGML3() throws JAXBException {
-        createContext();
-        final TimePeriodBound begin = new TimePeriodBound.GML3(null, "before");
-        final TimePeriodBound end   = new TimePeriodBound.GML3(new DummyInstant(date("2007-12-30 23:00:00")), "after");
-        testPeriod(begin, end,
-                "<gml:TimePeriod xmlns:gml=\"" + Namespaces.GML + "\">\n" +
-                "  <gml:beginPosition indeterminatePosition=\"before\"/>\n" +
-                "  <gml:endPosition>2007-12-31</gml:endPosition>\n" +
-                "</gml:TimePeriod>\n", false);
-    }
-
-    /**
-     * Same test than {@link #testSimplifiedPeriodGML3()}, but without end boundary.
-     * The test is executed using an arbitrary locale and timezone.
-     *
-     * @throws JAXBException If an error occurred while marshalling.
-     */
-    @Test
-    public void testAfterPeriodGML3() throws JAXBException {
-        createContext();
-        final TimePeriodBound begin = new TimePeriodBound.GML3(new DummyInstant(date("1992-01-01 23:00:00")), "before");
-        final TimePeriodBound end   = new TimePeriodBound.GML3(null, "after");
-        testPeriod(begin, end,
-                "<gml:TimePeriod xmlns:gml=\"" + Namespaces.GML + "\">\n" +
-                "  <gml:beginPosition>1992-01-02</gml:beginPosition>\n" +
-                "  <gml:endPosition indeterminatePosition=\"after\"/>\n" +
-                "</gml:TimePeriod>\n", false);
-    }
 }
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
index d66300d..ea37585 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DefinitionURITest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.util;
 
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -190,7 +190,7 @@
     }
 
     /**
-     * Tests {@link DefinitionURI#format(String, Identifier)}.
+     * Tests {@link DefinitionURI#format(String, ReferenceIdentifier)}.
      */
     @Test
     public void testToURN() {
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java b/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java
index 3832882..223152e 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java
@@ -28,7 +28,6 @@
 import javax.xml.bind.annotation.XmlElementRefs;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.CodeList;
-import org.opengis.util.ControlledVocabulary;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Obligation;
 import org.opengis.annotation.Specification;
@@ -416,7 +415,7 @@
             testingClass = type.getCanonicalName();
             UML uml = type.getAnnotation(UML.class);
             assertNotNull("Missing @UML annotation.", uml);
-            if (!ControlledVocabulary.class.isAssignableFrom(type)) {
+            if (!CodeList.class.isAssignableFrom(type)) {
                 for (final Method method : type.getDeclaredMethods()) {
                     testingMethod = method.getName();
                     if (!isIgnored(method) && !isExtension(method)) {
@@ -444,7 +443,7 @@
     public void testPackageAnnotations() {
         final Set<Package> packages = new HashSet<Package>();
         for (final Class<?> type : types) {
-            if (!ControlledVocabulary.class.isAssignableFrom(type)) {
+            if (!CodeList.class.isAssignableFrom(type)) {
                 testingClass = type.getCanonicalName();
                 final Class<?> impl = getImplementation(type);
                 if (impl != null) {
@@ -485,7 +484,7 @@
     @DependsOnMethod("testInterfaceAnnotations")
     public void testImplementationAnnotations() {
         for (final Class<?> type : types) {
-            if (ControlledVocabulary.class.isAssignableFrom(type)) {
+            if (CodeList.class.isAssignableFrom(type)) {
                 // Skip code lists, since they are not the purpose of this test.
                 continue;
             }
@@ -544,7 +543,7 @@
     @DependsOnMethod("testImplementationAnnotations")
     public void testMethodAnnotations() {
         for (final Class<?> type : types) {
-            if (ControlledVocabulary.class.isAssignableFrom(type)) {
+            if (CodeList.class.isAssignableFrom(type)) {
                 // Skip code lists, since they are not the purpose of this test.
                 continue;
             }
@@ -672,7 +671,7 @@
                     assertEquals("Wrong @XmlElement.", uml.identifier(), element.name());
                 }
                 final String namespace = assertExpectedNamespace(element.namespace(), wrapper.type, uml);
-                if (!ControlledVocabulary.class.isAssignableFrom(type)) {
+                if (!CodeList.class.isAssignableFrom(type)) {
                     final String expected = getNamespace(getImplementation(type));
                     if (expected != null) { // 'assertNotNull' is 'testImplementationAnnotations()' job.
                         assertEquals("Inconsistent @XmlRootElement namespace.", expected, namespace);
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java b/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
index 4ba279e..6a53427 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/Assert.java
@@ -48,7 +48,7 @@
  * @version 0.7
  * @module
  */
-public strictfp class Assert extends org.opengis.test.Assert {
+public strictfp class Assert extends GeoapiAssert {
     /**
      * For subclass constructor only.
      */
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/GeoapiAssert.java b/core/sis-utility/src/test/java/org/apache/sis/test/GeoapiAssert.java
new file mode 100644
index 0000000..6914ff5
--- /dev/null
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/GeoapiAssert.java
@@ -0,0 +1,196 @@
+/*
+ * 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.test;
+
+import org.opengis.metadata.citation.Citation;
+import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.util.InternationalString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ * Temporary class for test methods that are expected to be provided in next GeoAPI release.
+ * Those methods are defined in a separated class in order to make easier for us to identify
+ * which methods may be removed from SIS (actually moved to GeoAPI) in a future GeoAPI release.
+ *
+ * <p>This class is needed for Apache SIS trunk, since the later is linked to GeoAPI official release.
+ * But this class can be removed on Apache SIS branches which are linked to a GeoAPI development branch.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+strictfp class GeoapiAssert extends org.opengis.test.Assert {
+    /**
+     * A flag for code that are pending next GeoAPI release before to be enabled.
+     * This flag is always set to {@code false}, except occasionally just before
+     * a GeoAPI release for testing purpose. It shall be used as below:
+     *
+     * {@preformat java
+     *     if (PENDING_NEXT_GEOAPI_RELEASE) {
+     *         // Do some stuff here.
+     *     }
+     * }
+     *
+     * The intend is to make easier to identify test cases that fail with the current version
+     * of the {@code geoapi-conformance} module, but should pass with the development snapshot.
+     */
+    public static final boolean PENDING_NEXT_GEOAPI_RELEASE = false;
+
+    /**
+     * The keyword for unrestricted value in {@link String} arguments.
+     */
+    private static final String UNRESTRICTED = "##unrestricted";
+
+    /**
+     * For subclass constructor only.
+     */
+    GeoapiAssert() {
+    }
+
+    /**
+     * Returns the concatenation of the given message with the given extension.
+     * This method returns the given extension if the message is null or empty.
+     *
+     * <p>Invoking this method is equivalent to invoking {@code nonNull(message) + ext},
+     * but avoid the creation of temporary objects in the common case where the message
+     * is null.</p>
+     *
+     * @param  message The message, or {@code null}.
+     * @param  ext The extension to append after the message.
+     * @return The concatenated string.
+     */
+    private static String concat(String message, final String ext) {
+        if (message == null || (message = message.trim()).isEmpty()) {
+            return ext;
+        }
+        return message + ' ' + ext;
+    }
+
+    /**
+     * Verifies if we expected a null value, then returns {@code true} if the value is null as expected.
+     */
+    private static boolean isNull(final String message, final Object expected, final Object actual) {
+        final boolean isNull = (actual == null);
+        if (isNull != (expected == null)) {
+            fail(concat(message, isNull ? "Value is null." : "Expected null."));
+        }
+        return isNull;
+    }
+
+    /**
+     * Asserts that the title or an alternate title of the given citation is equal to the given string.
+     * This method is typically used for testing if a citation stands for the OGC, OGP or EPSG authority
+     * for instance. Such abbreviations are often declared as {@linkplain Citation#getAlternateTitles()
+     * alternate titles} rather than the main {@linkplain Citation#getTitle() title}, but this method
+     * tests both for safety.
+     *
+     * @param message  Header of the exception message in case of failure, or {@code null} if none.
+     * @param expected The expected title or alternate title.
+     * @param actual   The citation to test.
+     */
+    public static void assertAnyTitleEquals(final String message, final String expected, final Citation actual) {
+        if (isNull(message, expected, actual)) {
+            return;
+        }
+        InternationalString title = actual.getTitle();
+        if (title != null && expected.equals(title.toString())) {
+            return;
+        }
+        for (final InternationalString t : actual.getAlternateTitles()) {
+            if (expected.equals(t.toString())) {
+                return;
+            }
+        }
+        fail(concat(message, '"' + expected + "\" not found in title or alternate titles."));
+    }
+
+    /**
+     * Asserts that the given identifier is equals to the given authority, code space, version and code.
+     * If any of the above-cited properties is {@code ""##unrestricted"}, then it will not be verified.
+     * This flexibility is useful in the common case where a test accepts any {@code version} value.
+     *
+     * @param message    Header of the exception message in case of failure, or {@code null} if none.
+     * @param authority  The expected authority title or alternate title (may be {@code null}), or {@code "##unrestricted"}.
+     * @param codeSpace  The expected code space (may be {@code null}), or {@code "##unrestricted"}.
+     * @param version    The expected version    (may be {@code null}), or {@code "##unrestricted"}.
+     * @param code       The expected code value (may be {@code null}), or {@code "##unrestricted"}.
+     * @param actual     The identifier to test.
+     */
+    public static void assertIdentifierEquals(final String message, final String authority, final String codeSpace,
+            final String version, final String code, final ReferenceIdentifier actual)
+    {
+        if (actual == null) {
+            fail(concat(message, "Identifier is null"));
+        } else {
+            if (!UNRESTRICTED.equals(authority)) assertAnyTitleEquals(message,                      authority, actual.getAuthority());
+            if (!UNRESTRICTED.equals(codeSpace)) assertEquals (concat(message, "Wrong code space"), codeSpace, actual.getCodeSpace());
+            if (!UNRESTRICTED.equals(version))   assertEquals (concat(message, "Wrong version"),    version,   actual.getVersion());
+            if (!UNRESTRICTED.equals(code))      assertEquals (concat(message, "Wrong code"),       code,      actual.getCode());
+        }
+    }
+
+    /**
+     * Asserts that all axes in the given coordinate system are pointing toward the given directions, in the same order.
+     *
+     * @param message  Header of the exception message in case of failure, or {@code null} if none.
+     * @param cs       The coordinate system to test.
+     * @param expected The expected axis directions.
+     */
+    public static void assertAxisDirectionsEqual(String message,
+            final CoordinateSystem cs, final AxisDirection... expected)
+    {
+        assertEquals(concat(message, "Wrong coordinate system dimension."), expected.length, cs.getDimension());
+        message = concat(message, "Wrong axis direction.");
+        for (int i=0; i<expected.length; i++) {
+            assertEquals(message, expected[i], cs.getAxis(i).getDirection());
+        }
+    }
+
+    /**
+     * Asserts that the given matrix is equals to the expected one, up to the given tolerance value.
+     *
+     * @param message   Header of the exception message in case of failure, or {@code null} if none.
+     * @param expected  The expected matrix, which may be {@code null}.
+     * @param actual    The matrix to compare, or {@code null}.
+     * @param tolerance The tolerance threshold.
+     */
+    public static void assertMatrixEquals(final String message, final Matrix expected, final Matrix actual, final double tolerance) {
+        if (isNull(message, expected, actual)) {
+            return;
+        }
+        final int numRow = actual.getNumRow();
+        final int numCol = actual.getNumCol();
+        assertEquals("numRow", expected.getNumRow(), numRow);
+        assertEquals("numCol", expected.getNumCol(), numCol);
+        for (int j=0; j<numRow; j++) {
+            for (int i=0; i<numCol; i++) {
+                final double e = expected.getElement(j,i);
+                final double a = actual.getElement(j,i);
+                if (!(StrictMath.abs(e - a) <= tolerance) && Double.doubleToLongBits(a) != Double.doubleToLongBits(e)) {
+                    fail("Matrix.getElement(" + j + ", " + i + "): expected " + e + " but got " + a);
+                }
+            }
+        }
+    }
+}
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/LoggingWatcher.java b/core/sis-utility/src/test/java/org/apache/sis/test/LoggingWatcher.java
index baec9d3..72cc27c 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/LoggingWatcher.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/LoggingWatcher.java
@@ -24,11 +24,13 @@
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import java.util.logging.SimpleFormatter;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
 
 import static org.junit.Assert.*;
 
+// Branch-specific imports
+import org.junit.rules.TestWatchman;
+import org.junit.runners.model.FrameworkMethod;
+
 
 /**
  * Watches the logs sent to the given logger.
@@ -61,7 +63,7 @@
  * @version 0.7
  * @module
  */
-public final strictfp class LoggingWatcher extends TestWatcher implements Filter {
+public final strictfp class LoggingWatcher extends TestWatchman implements Filter {
     /**
      * The logged messages.
      */
@@ -106,7 +108,7 @@
      * @see #isLoggable(LogRecord)
      */
     @Override
-    protected final void starting(final Description description) {
+    public final void starting(final FrameworkMethod description) {
         assertNull(logger.getFilter());
         logger.setFilter(this);
     }
@@ -118,7 +120,7 @@
      * @param description A description of the JUnit test that finished.
      */
     @Override
-    protected final void finished(final Description description) {
+    public final void finished(final FrameworkMethod description) {
         logger.setFilter(null);
     }
 
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java b/core/sis-utility/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
index 749540b..67633ec 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
@@ -25,9 +25,9 @@
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.jaxb.gco.GO_GenericName;
 
@@ -44,7 +44,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()}.
      */
@@ -102,7 +102,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;
     }
 
@@ -162,19 +162,7 @@
      * @return The identifiers of this object.
      */
     @Override
-    public final Set<Identifier> getIdentifiers() {
-        return null;
-    }
-
-    /**
-     * Returns the description (currently null).
-     *
-     * @return The description associated to this object.
-     *
-     * @since 0.5
-     */
-    @Override
-    public InternationalString getDescription() {
+    public final Set<ReferenceIdentifier> getIdentifiers() {
         return null;
     }
 
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/mock/MetadataMock.java b/core/sis-utility/src/test/java/org/apache/sis/test/mock/MetadataMock.java
index d037610..64fc375 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/mock/MetadataMock.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/mock/MetadataMock.java
@@ -19,22 +19,15 @@
 import java.util.Date;
 import java.util.Locale;
 import java.util.Collection;
-import java.util.Collections;
-import java.nio.charset.Charset;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.Metadata;
-import org.opengis.metadata.MetadataScope;
 import org.opengis.metadata.MetadataExtensionInformation;
 import org.opengis.metadata.ApplicationSchemaInformation;
 import org.opengis.metadata.PortrayalCatalogueReference;
 import org.opengis.metadata.acquisition.AcquisitionInformation;
-import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.CitationDate;
-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;
@@ -43,7 +36,6 @@
 import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.quality.DataQuality;
-import org.opengis.metadata.lineage.Lineage;
 import org.opengis.metadata.spatial.SpatialRepresentation;
 import org.opengis.referencing.ReferenceSystem;
 import org.apache.sis.internal.jaxb.gmd.LocaleAdapter;
@@ -89,31 +81,12 @@
      * @return {@code null}.
      */
     @Override
-    public Identifier getMetadataIdentifier() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public String getFileIdentifier() {
         return null;
     }
 
     /**
-     * Returns {@link #language} in a singleton set or an empty set.
-     *
-     * @return {@link #language}
-     */
-    @Override
-    public Collection<Locale> getLanguages() {
-        return (language != null) ? Collections.<Locale>singleton(language) : Collections.<Locale>emptySet();
-    }
-
-    /**
      * Returns {@link #language}.
      *
      * @return {@link #language}
@@ -139,15 +112,6 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<Charset> getCharacterSets() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public CharacterSet getCharacterSet() {
         return null;
@@ -158,15 +122,6 @@
      * @return {@code null}.
      */
     @Override
-    public Citation getParentMetadata() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public String getParentIdentifier() {
         return null;
@@ -177,15 +132,6 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<? extends MetadataScope> getMetadataScopes() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public Collection<ScopeCode> getHierarchyLevels() {
         return null;
@@ -206,16 +152,7 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<? extends Responsibility> getContacts() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
-    public Collection<? extends CitationDate> getDateInfo() {
+    public Collection<? extends ResponsibleParty> getContacts() {
         return null;
     }
 
@@ -234,15 +171,6 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<? extends Citation> getMetadataStandards() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public String getMetadataStandardName() {
         return null;
@@ -263,33 +191,6 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<? extends Citation> getMetadataProfiles() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
-    public Collection<? extends Citation> getAlternativeMetadataReferences() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
-    public Collection<? extends OnlineResource> getMetadataLinkages() {
-        return null;
-    }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
     @Deprecated
     public String getDataSetUri() {
         return null;
@@ -345,7 +246,7 @@
      * @return {@code null}.
      */
     @Override
-    public Collection<? extends Distribution> getDistributionInfo() {
+    public Distribution getDistributionInfo() {
         return null;
     }
 
@@ -402,13 +303,4 @@
     public Collection<? extends AcquisitionInformation> getAcquisitionInformation() {
         return null;
     }
-
-    /**
-     * Undefined property.
-     * @return {@code null}.
-     */
-    @Override
-    public Collection<? extends Lineage> getResourceLineages() {
-        return null;
-    }
 }
diff --git a/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java b/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
index caec4ff..75b2624 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
@@ -143,7 +143,6 @@
     org.apache.sis.internal.jaxb.ModifiableIdentifierMapTest.class,
     org.apache.sis.internal.jaxb.gco.StringAdapterTest.class,
     org.apache.sis.internal.jaxb.gco.PropertyTypeTest.class,
-    org.apache.sis.internal.jaxb.gmd.EnumAdapterTest.class,
     org.apache.sis.internal.jaxb.gmd.LanguageCodeTest.class,
     org.apache.sis.internal.jaxb.gml.TimePeriodTest.class,
     org.apache.sis.internal.jaxb.gml.MeasureTest.class,
diff --git a/core/sis-utility/src/test/java/org/apache/sis/util/collection/TreeTableFormatTest.java b/core/sis-utility/src/test/java/org/apache/sis/util/collection/TreeTableFormatTest.java
index 3ecc81a..12a3df0 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/util/collection/TreeTableFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/util/collection/TreeTableFormatTest.java
@@ -255,7 +255,7 @@
         tf = new TreeTableFormat(Locale.FRENCH, null);
         assertMultilinesEquals(
                 "Root\n" +
-                "  ├─CodeList…… Point de contact\n" +
+                "  ├─CodeList…… Point of contact\n" + // Not yet localized.
                 "  ├─Enum……………… Half down\n" +        // No localization provided.
                 "  └─i18n……………… Une phrase en français\n", tf.format(table));
 
diff --git a/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java b/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
index 0c93269..7d00587 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
@@ -30,11 +30,11 @@
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.PixelInCell;
 import org.opengis.referencing.cs.AxisDirection;
-import org.opengis.parameter.ParameterDirection;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.PENDING_NEXT_GEOAPI_RELEASE;
 
 
 /**
@@ -122,21 +122,6 @@
     }
 
     /**
-     * Tests the {@link Types#forEnumName(Class, String)} method with an enumeration from GeoAPI.
-     * Such enumerations implement the {@link org.opengis.util.ControlledVocabulary} interface.
-     *
-     * @since 0.5
-     */
-    @Test
-    public void testForGeoapiEnumName() {
-        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "IN_OUT"));
-        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "INOUT"));
-        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "in out"));
-        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "in/out"));
-        assertNull(Types.forEnumName(ParameterDirection.class, "out/in"));
-    }
-
-    /**
      * Tests the {@link Types#forCodeName(Class, String, boolean)} method.
      */
     @Test
@@ -151,8 +136,11 @@
         assertSame(PixelInCell.CELL_CORNER, Types.forCodeName(PixelInCell.class, "cellCorner",  false));
         assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cell center", false));
         assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cellCenter",  false));
-        assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cell centre", false));
-        assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cellCentre",  false));
+
+        if (PENDING_NEXT_GEOAPI_RELEASE) {
+            assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cell centre", false));
+            assertSame(PixelInCell.CELL_CENTER, Types.forCodeName(PixelInCell.class, "cellCentre",  false));
+        }
     }
 
     /**
@@ -208,7 +196,6 @@
      */
     @Test
     public void testGetListName() {
-        assertEquals("SV_ParameterDirection",   Types.getListName(ParameterDirection.IN_OUT));
         assertEquals("CS_AxisDirection",        Types.getListName(AxisDirection     .NORTH));
         assertEquals("CI_OnLineFunctionCode",   Types.getListName(OnLineFunction    .DOWNLOAD));
         assertEquals("MD_ImagingConditionCode", Types.getListName(ImagingCondition  .BLURRED_IMAGE));
@@ -219,7 +206,6 @@
      */
     @Test
     public void testGetCodeName() {
-        assertEquals("in/out",       Types.getCodeName(ParameterDirection.IN_OUT));
         assertEquals("north",        Types.getCodeName(AxisDirection     .NORTH));
         assertEquals("download",     Types.getCodeName(OnLineFunction    .DOWNLOAD));
         assertEquals("blurredImage", Types.getCodeName(ImagingCondition  .BLURRED_IMAGE));
diff --git a/core/sis-utility/src/test/java/org/apache/sis/xml/NilReasonTest.java b/core/sis-utility/src/test/java/org/apache/sis/xml/NilReasonTest.java
index 760df62..05e83d5 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/xml/NilReasonTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/xml/NilReasonTest.java
@@ -19,7 +19,7 @@
 import java.net.URISyntaxException;
 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.apache.sis.util.LenientComparable;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.ArraysExt;
@@ -288,7 +288,7 @@
         assertTrue (c.equals(e2, ComparisonMode.DEBUG));
 
         // Following object should alway be different because it does not implement the same interface.
-        final Responsibility r1 = NilReason.TEMPLATE.createNilObject(Responsibility.class);
+        final ResponsibleParty r1 = NilReason.TEMPLATE.createNilObject(ResponsibleParty.class);
         assertFalse(c.equals(r1, ComparisonMode.STRICT));
         assertFalse(c.equals(r1, ComparisonMode.BY_CONTRACT));
         assertFalse(c.equals(r1, ComparisonMode.IGNORE_METADATA));
diff --git a/ide-project/NetBeans/README.txt b/ide-project/NetBeans/README.txt
index b7cafed..6724fc5 100644
--- a/ide-project/NetBeans/README.txt
+++ b/ide-project/NetBeans/README.txt
@@ -4,37 +4,6 @@
 
 
 ==============================================================================
-Installation
-==============================================================================
-The configuration provided in this directory requires a checkout of GeoAPI
-source code. The recommended installation steps is as below (from the root
-directory of all SIS-related projects):
-
-  mkdir SIS
-  svn checkout http://svn.apache.org/repos/asf/sis/branches/JDK6 SIS/JDK6
-  mkdir GeoAPI
-  git clone http://github.com/opengeospatial/geoapi GeoAPI/master
-
-Above commands should create the following directory structure:
-
-  +-- GeoAPI
-  |   +-- master
-  |       +-- README.txt
-  |       +-- etc...
-  +-- SIS
-      +-- JDK6
-          +-- README
-          +-- etc...
-
-If a different directory layout is desired, this is possible provided that
-the following line is added to "nbproject/private/private.properties" file:
-
-  project.GeoAPI = <path to your GeoAPI checkout>/ide-project/NetBeans
-
-
-
-
-==============================================================================
 Recommendations for NetBeans project configuration changes
 ==============================================================================
 There is 3 important files that should be edited BY HAND for preserving user-
diff --git a/ide-project/NetBeans/build.xml b/ide-project/NetBeans/build.xml
index ea0b9dc..aafab68 100644
--- a/ide-project/NetBeans/build.xml
+++ b/ide-project/NetBeans/build.xml
@@ -32,6 +32,11 @@
     before it can be built by the NetBeans IDE.
   -->
   <target name="-post-compile">
+    <copy todir="${build.classes.dir}/org/apache/sis/util/iso">
+      <fileset dir="${project.root}/core/sis-utility/src/main/resources/org/apache/sis/util/iso">
+        <include name="class-index.properties"/>
+      </fileset>
+    </copy>
     <copy todir="${build.classes.dir}/org/apache/sis/util/resources">
       <fileset dir="${project.root}/core/sis-utility/target/generated-resources/org/apache/sis/util/resources">
         <include name="*.utf"/>
diff --git a/ide-project/NetBeans/nbproject/build-impl.xml b/ide-project/NetBeans/nbproject/build-impl.xml
index 7dd2c22..181add9 100644
--- a/ide-project/NetBeans/nbproject/build-impl.xml
+++ b/ide-project/NetBeans/nbproject/build-impl.xml
@@ -19,7 +19,7 @@
   - cleanup
 
         -->
-<project 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" basedir=".." default="default" name="Apache_SIS_for_JDK6-impl">
+<project 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" basedir=".." default="default" name="Apache_SIS_on_GeoAPI_3.0-impl">
     <fail message="Please build using Ant 1.8.0 or higher.">
         <condition>
             <not>
@@ -533,7 +533,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_for_JDK6" 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.0" testname="TestNG tests" workingDir="${work.dir}">
                     <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
                     <propertyset>
                         <propertyref prefix="test-sys-prop."/>
@@ -708,7 +708,7 @@
                 <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
                     <isset property="test.method"/>
                 </condition>
-                <condition else="-suitename Apache_SIS_for_JDK6 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                <condition else="-suitename Apache_SIS_on_GeoAPI_3.0 -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"/>
@@ -1000,7 +1000,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 for JDK6 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.0 was already built"/>
     </target>
     <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -1010,14 +1010,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"/>
-        </antcall>
     </target>
     <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
     <target depends="init" name="-check-automatic-build">
@@ -1579,7 +1571,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 for JDK6 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.0 was already built"/>
     </target>
     <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -1589,14 +1581,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"/>
-        </antcall>
     </target>
     <target depends="init" name="-do-clean">
         <delete dir="${build.dir}"/>
diff --git a/ide-project/NetBeans/nbproject/project.properties b/ide-project/NetBeans/nbproject/project.properties
index 2124e3d..ebf8e6d 100644
--- a/ide-project/NetBeans/nbproject/project.properties
+++ b/ide-project/NetBeans/nbproject/project.properties
@@ -66,17 +66,11 @@
 test.fra-profile.dir = ${project.root}/profiles/sis-french-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.0.0
 unit-api.version     = 0.6.1
 jsr275.version       = 0.9.3
 jama.version         = 1.0.3
@@ -102,7 +96,7 @@
 maven.repository   = ${user.home}/.m2/repository
 endorsed.classpath=
 javac.classpath=\
-    ${project.GeoAPI}/dist/geoapi.jar:\
+    ${maven.repository}/org/opengis/geoapi/${geoapi.version}/geoapi-${geoapi.version}.jar:\
     ${maven.repository}/org/unitsofmeasurement/unit-api/${unit-api.version}/unit-api-${unit-api.version}.jar:\
     ${maven.repository}/javax/measure/jsr-275/${jsr275.version}/jsr-275-${jsr275.version}.jar:\
     ${maven.repository}/com/esri/geometry/esri-geometry-api/${geometry.version}/esri-geometry-api-${geometry.version}.jar:\
@@ -119,8 +113,10 @@
     ${javac.classpath}:\
     ${maven.repository}/junit/junit/${junit.version}/junit-${junit.version}.jar:\
     ${maven.repository}/org/hamcrest/hamcrest-core/${hamcrest.version}/hamcrest-core-${hamcrest.version}.jar:\
+    ${maven.repository}/org/opengis/geoapi-conformance/${geoapi.version}/geoapi-conformance-${geoapi.version}.jar:\
     ${maven.repository}/gov/nist/math/jama/${jama.version}/jama-${jama.version}.jar:\
-    ${project.GeoAPI}/dist/geoapi-tests.jar:\
+    ${maven.repository}/org/opengis/wrapper/geoapi-netcdf/${geoapi.version}/geoapi-netcdf-${geoapi.version}.jar:\
+    ${maven.repository}/org/opengis/wrapper/geoapi-netcdf/${geoapi.version}/geoapi-netcdf-${geoapi.version}-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 d66aba9..4110f21 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 for JDK6</name>
+            <name>Apache SIS on GeoAPI 3.0</name>
             <source-roots>
                 <root id="src.local-src.dir" name="Local sources (unversioned)"/>
                 <root id="src.webapp.dir" name="Web application"/>
@@ -47,16 +47,6 @@
                 <root id="test.fra-profile.dir" name="Test French 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>bitmask</word>
diff --git a/pom.xml b/pom.xml
index e35bb10..305ed4a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
        ============================================================== -->
   <groupId>org.apache.sis</groupId>
   <artifactId>parent</artifactId>
-  <version>0.8-jdk6-SNAPSHOT</version>
+  <version>0.8-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>Apache SIS</name>
@@ -341,7 +341,7 @@
       </dependency>
       <dependency>
         <groupId>org.opengis</groupId>
-        <artifactId>geoapi-pending</artifactId>
+        <artifactId>geoapi</artifactId>
         <version>${geoapi.version}</version>
       </dependency>
       <dependency>
@@ -425,7 +425,7 @@
     <maven.compile.source>1.6</maven.compile.source>
     <maven.compile.target>1.6</maven.compile.target>
     <sis.plugin.version>${project.version}</sis.plugin.version>
-    <geoapi.version>4.0-SNAPSHOT</geoapi.version>
+    <geoapi.version>3.0.0</geoapi.version>
   </properties>
 
   <profiles>
@@ -609,12 +609,9 @@
           <breakiterator>true</breakiterator>                   <!-- Better boundary detection when determining the end of the first sentence. -->
           <validateLinks>true</validateLinks>                   <!-- Validates content of package-list resources. -->
           <links>
-            <link>http://www.geoapi.org/snapshot/pending</link>
+            <link>http://www.geoapi.org/3.0/javadoc</link>
           </links>
 
-          <additionalparam>
-          </additionalparam>
-
           <!-- Separates packages on the overview page into the groups specified. -->
           <groups>
             <group>
@@ -652,7 +649,7 @@
           </groups>
 
           <!-- Internal packages to hide from javadoc. -->
-          <excludePackageNames>org.apache.sis.internal:org.apache.sis.util.resources:org.apache.sis.referencing.operation.provider:com</excludePackageNames>
+          <excludePackageNames>org.apache.sis.internal:org.apache.sis.util.resources:org.apache.sis.referencing.operation.provider:com:org.opengis</excludePackageNames>
 
           <!-- Custom taglets, some of them implemented in Java. -->
           <tags>
@@ -745,17 +742,6 @@
     </pluginRepository>
   </pluginRepositories>
 
-  <!-- Used for GeoAPI snapshots and latest vecmath releases
-       on SIS branches only. Shall be removed on SIS trunk. -->
-  <repositories>
-    <repository>
-      <id>geotoolkit</id>
-      <name>Geotoolkit.org repository</name>
-      <url>http://maven.geotoolkit.org</url>
-    </repository>
-  </repositories>
-
-
 
   <!-- ==============================================================
          Group of modules to build in approximate dependency order.
diff --git a/profiles/pom.xml b/profiles/pom.xml
index 964154e..2284bb1 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -94,7 +94,7 @@
     </dependency>
     <dependency>
       <groupId>org.opengis</groupId>
-      <artifactId>geoapi-pending</artifactId>
+      <artifactId>geoapi</artifactId>
     </dependency>
 
     <!-- Test dependencies -->
diff --git a/profiles/sis-french-profile/pom.xml b/profiles/sis-french-profile/pom.xml
index 5bb2e47..e92d3ca 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-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 ec2f147..eff8306 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 cd80d19..0270473 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 d1cd5fc..f3655f6 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
@@ -19,7 +19,7 @@
 import java.util.Collection;
 import java.util.Collections;
 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.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
@@ -59,9 +59,9 @@
     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 = Collections.<Responsibility>singleton(new DefaultResponsibleParty(TestUtilities.getSingleton(r)));
+            r = Collections.<ResponsibleParty>singleton(new DefaultResponsibleParty(TestUtilities.getSingleton(r)));
         }
         citation.setCitedResponsibleParties(r);
         final DirectReferenceSystem refSys = new DirectReferenceSystem(new ImmutableIdentifier(citation, null, "4326"));
diff --git a/storage/pom.xml b/storage/pom.xml
index 2bc32d4..dab6523 100644
--- a/storage/pom.xml
+++ b/storage/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache.sis</groupId>
     <artifactId>parent</artifactId>
-    <version>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -113,7 +113,7 @@
     </dependency>
     <dependency>
       <groupId>org.opengis</groupId>
-      <artifactId>geoapi-pending</artifactId>
+      <artifactId>geoapi</artifactId>
     </dependency>
 
     <!-- Test dependencies -->
diff --git a/storage/sis-netcdf/pom.xml b/storage/sis-netcdf/pom.xml
index 5eb7904..f07a7d5 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
@@ -119,20 +119,6 @@
       <optional>true</optional>
     </dependency>
 
-    <!-- Leverage GeoAPI tests. -->
-    <dependency>
-      <groupId>org.opengis.wrapper</groupId>
-      <artifactId>geoapi-netcdf</artifactId>
-      <version>${geoapi.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.opengis.wrapper</groupId>
-      <artifactId>geoapi-netcdf</artifactId>
-      <version>${geoapi.version}</version>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-jdk14</artifactId>
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 3297deb..f5088c1 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
@@ -48,6 +48,7 @@
 
 import org.opengis.util.CodeList;
 import org.apache.sis.util.iso.Types;
+import org.apache.sis.util.iso.DefaultNameFactory;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.iso.DefaultMetadataScope;
@@ -154,8 +155,11 @@
 
     /**
      * The name factory, created when first needed.
+     *
+     * The type is {@link NameFactory} on the JDK6 branch. However we have to force the SIS
+     * implementation on the GeoAPI 3.0 branch because the older interface is missing a method.
      */
-    private transient NameFactory nameFactory;
+    private transient DefaultNameFactory nameFactory;
 
     /**
      * The contact, used at metadata creation time for avoiding to construct identical objects
@@ -172,7 +176,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;
 
     /**
      * Creates a new <cite>NetCDF to ISO</cite> mapper for the given source.
@@ -388,7 +392,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)
             throws IOException
     {
         final String individualName   = stringValue(keys.NAME);
@@ -406,17 +410,16 @@
          * 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;
-        Contact        contact        = null;
-        Address        address        = null;
-        OnlineResource resource       = null;
+        ResponsibleParty responsibility = pointOfContact;
+        Contact          contact        = null;
+        Address          address        = null;
+        OnlineResource   resource       = null;
         if (responsibility != null) {
-            final Party party = first(responsibility.getParties());
-            if (party != null) {
-                contact = first(party.getContactInfo());
+            { // Additional indentation for having the same level than SIS branches for GeoAPI snapshots (makes merges easier).
+                contact = responsibility.getContactInfo();
                 if (contact != null) {
-                    address  = first(contact.getAddresses());
-                    resource = first(contact.getOnlineResources());
+                    address  = contact.getAddress();
+                    resource = contact.getOnlineResource();
                 }
                 if (!canShare(resource, url)) {
                     resource       = null;
@@ -429,14 +432,9 @@
                     responsibility = null;
                 }
                 if (responsibility != null) {
-                    if (party instanceof Organisation) {
-                        // Individual (if any) is considered an organisation member. See comment in next block.
-                        if (!canShare(party.getName(), organisationName) ||
-                            !canShare(first(((Organisation) party).getIndividual()).getName(), individualName))
-                        {
-                            responsibility = null;
-                        }
-                    } else if (!canShare(party.getName(), individualName)) {
+                    if (!canShare(responsibility.getOrganisationName(), organisationName) ||
+                        !canShare(responsibility.getIndividualName(),   individualName))
+                    {
                         responsibility = null;
                     }
                 }
@@ -456,10 +454,11 @@
             if (individualName != null || organisationName != null || contact != null) { // Do not test role.
                 AbstractParty party = null;
                 if (individualName   != null) party = new DefaultIndividual(individualName, null, null);
-                if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (Individual) party, null);
+                if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (DefaultIndividual) party, null);
                 if (party            == null) party = new AbstractParty(); // We don't know if this is an individual or an organisation.
                 if (contact          != null) party.setContactInfo(singleton(contact));
-                responsibility = new DefaultResponsibility(role, null, party);
+                responsibility = new DefaultResponsibleParty(role);
+                ((DefaultResponsibleParty) responsibility).setParties(singleton(party));
             }
         }
         return responsibility;
@@ -496,20 +495,20 @@
         if (issued   != null) citation.getDates()  .add  (new DefaultCitationDate(issued,   DateType.PUBLICATION));
         if (pointOfContact != null) {
             // Same responsible party than the contact, except for the role.
-            final DefaultResponsibility np = new DefaultResponsibility(pointOfContact);
+            final DefaultResponsibleParty np = new DefaultResponsibleParty(pointOfContact);
             np.setRole(Role.ORIGINATOR);
             citation.setCitedResponsibleParties(singleton(np));
         }
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final Responsibility contributor = createResponsibleParty(CONTRIBUTOR, false);
+            final ResponsibleParty contributor = createResponsibleParty(CONTRIBUTOR, false);
             if (contributor != null && contributor != pointOfContact) {
                 addIfAbsent(citation.getCitedResponsibleParties(), contributor);
             }
         }
         decoder.setSearchPath(searchPath);
         if (references != null) {
-            citation.setOtherCitationDetails(singleton(new SimpleInternationalString(references)));
+            citation.setOtherCitationDetails(new SimpleInternationalString(references));
         }
         return citation.isEmpty() ? null : citation;
     }
@@ -543,11 +542,11 @@
                 if (identification == null) {
                     identification = new DefaultDataIdentification();
                 }
-                if (topic    != null) addIfAbsent(identification.getTopicCategories(), forEnumName(TopicCategory.class, topic));
+                if (topic    != null) addIfAbsent(identification.getTopicCategories(), forCodeName(TopicCategory.class, topic));
                 if (type     != null) addIfAbsent(identification.getSpatialRepresentationTypes(), forCodeName(SpatialRepresentationType.class, type));
                 if (standard != null) addIfAbsent(identification.getDescriptiveKeywords(), standard);
                 if (keywords != null) addIfAbsent(identification.getDescriptiveKeywords(), keywords);
-                if (credits  != null) addIfAbsent(identification.getCredits(), new SimpleInternationalString(credits));
+                if (credits  != null) addIfAbsent(identification.getCredits(), credits);
                 if (license  != null) addIfAbsent(identification.getResourceConstraints(), constraints = new DefaultLegalConstraints(license));
                 if (access   != null) {
                     for (String keyword : access.split(KEYWORD_SEPARATOR)) {
@@ -586,8 +585,8 @@
         if (pointOfContact != null) {
             identification.setPointOfContacts(singleton(pointOfContact));
         }
-        addKeywords(identification, project,   KeywordType.PROJECT);
-        addKeywords(identification, publisher, KeywordType.DATA_CENTRE);
+        addKeywords(identification, project,   KeywordType.valueOf("project"));
+        addKeywords(identification, publisher, KeywordType.valueOf("dataCentre"));
         identification.setSupplementalInformation(toInternationalString(stringValue(COMMENT)));
         return identification;
     }
@@ -817,7 +816,7 @@
                 }
                 contents.put(dimensions, content);
             } else {
-                group = (DefaultAttributeGroup) first(content.getAttributeGroups());
+                group = first(content.getAttributeGroups());
             }
             if (group == null) {
                 group = new DefaultAttributeGroup();
@@ -855,7 +854,7 @@
         String name = variable.getName();
         if (name != null && !(name = name.trim()).isEmpty()) {
             if (nameFactory == null) {
-                nameFactory = DefaultFactories.forBuildin(NameFactory.class); // Real dependency injection to be used in a future version.
+                nameFactory = DefaultFactories.forBuildin(NameFactory.class, DefaultNameFactory.class); // Real dependency injection to be used in a future version.
             }
             band.setSequenceIdentifier(nameFactory.createMemberName(null, name,
                     nameFactory.createTypeName(null, variable.getDataTypeName())));
@@ -867,7 +866,7 @@
         final String units = variable.getUnitsString();
         if (units != null) try {
             band.setUnits(Units.valueOf(units));
-        } catch (IllegalArgumentException e) {
+        } catch (RuntimeException e) { // IllegalArgumentException or ClassCastException (specific to this branch).
             decoder.listeners.warning(errors().getString(Errors.Keys.CanNotAssignUnitToDimension_2, name, units), e);
         }
         return band;
@@ -953,7 +952,7 @@
          */
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final Responsibility party = createResponsibleParty(CREATOR, true);
+            final ResponsibleParty party = createResponsibleParty(CREATOR, true);
             if (party != null && party != pointOfContact) {
                 addIfAbsent(metadata.getContacts(), party);
                 if (pointOfContact == null) {
@@ -969,19 +968,18 @@
         DefaultDistribution distribution   = null;
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final Responsibility r = createResponsibleParty(PUBLISHER, false);
+            final ResponsibleParty r = createResponsibleParty(PUBLISHER, false);
             if (r != null) {
                 if (distribution == null) {
                     distribution = new DefaultDistribution();
-                    metadata.setDistributionInfo(singleton(distribution));
+                    metadata.setDistributionInfo(distribution);
                 }
                 final DefaultDistributor distributor = new DefaultDistributor(r);
                 // TODO: There is some transfert option, etc. that we could set there.
                 // See UnidataDD2MI.xsl for options for OPeNDAP, THREDDS, etc.
                 addIfAbsent(distribution.getDistributors(), distributor);
-                for (final Party party : r.getParties()) {
-                    publisher = addIfNonNull(publisher, party.getName());
-                }
+                publisher = addIfNonNull(publisher, r.getOrganisationName());
+                publisher = addIfNonNull(publisher, toInternationalString(r.getIndividualName()));
             }
             // Also add history.
             final String history = stringValue(HISTORY);
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/IOTestCase.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/IOTestCase.java
new file mode 100644
index 0000000..c43882f
--- /dev/null
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/IOTestCase.java
@@ -0,0 +1,93 @@
+/*
+ * 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.netcdf;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import ucar.nc2.NetcdfFile;
+
+import static org.junit.Assume.*;
+
+
+/**
+ * Placeholder for a GeoAPI 3.1 class which is missing in GeoAPI 3.0.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3
+ * @version 0.3
+ * @module
+ */
+public abstract strictfp class IOTestCase {
+    /**
+     * GeoAPI 3.1 constants copied here since this SIS branch depends on GeoAPI 3.0.
+     */
+    public static final String NCEP = "NCEP-SST.nc", CIP = "CIP.nc";
+
+    /**
+     * For subclass constructors only.
+     */
+    protected IOTestCase() {
+    }
+
+    /**
+     * Returns the given resource as a URL.
+     *
+     * @param  name The name of the resource.
+     * @return The resource as a URL.
+     */
+    public static URL getResource(final String name) {
+        final URL r = IOTestCase.class.getResource(name);
+        assumeNotNull(r);
+        return r;
+    }
+
+    /**
+     * Returns the given resource as an input stream.
+     *
+     * @param  name The name of the resource.
+     * @return The resource as an input stream.
+     */
+    public static InputStream getResourceAsStream(final String name) {
+        final InputStream in = IOTestCase.class.getResourceAsStream(name);
+        assumeNotNull(in);
+        return in;
+    }
+
+    /**
+     * Opens the given NetCDF file.
+     *
+     * @param  file The file name, typically one of the {@link #NCEP} or {@link #CIP} constants.
+     * @return The NetCDF file.
+     * @throws IOException If an error occurred while opening the file.
+     */
+    protected NetcdfFile open(final String file) throws IOException {
+        final URL url = getClass().getResource(file);
+        assumeNotNull(url);
+        assumeTrue("file".equals(url.getProtocol()));
+        final File f;
+        try {
+            f = new File(url.toURI());
+        } catch (URISyntaxException e) {
+            throw (IOException) new MalformedURLException(e.getLocalizedMessage()).initCause(e);
+        }
+        return NetcdfFile.open(f.getPath());
+    }
+}
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
index a060b87..31a5222 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/TestCase.java
@@ -26,7 +26,6 @@
 import org.apache.sis.util.logging.EmptyWarningListeners;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.system.Modules;
-import org.opengis.wrapper.netcdf.IOTestCase;
 import ucar.nc2.dataset.NetcdfDataset;
 import org.junit.AfterClass;
 
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
index 1064a0f..e041b2d 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
@@ -20,14 +20,14 @@
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
-import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.IOTestCase;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.DecoderTest;
 import org.apache.sis.internal.storage.ChannelDataInput;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.test.DependsOn;
 
-import static org.junit.Assert.*;
+import static org.junit.Assume.*;
 
 
 /**
@@ -72,7 +72,7 @@
      */
     public static Decoder createChannelDecoder(final String name) throws IOException, DataStoreException {
         final InputStream in = IOTestCase.class.getResourceAsStream(name);
-        assertNotNull(name, in);
+        assumeNotNull(name, in);
         final ChannelDataInput input = new ChannelDataInput(name,
                 Channels.newChannel(in), ByteBuffer.allocate(4096), false);
         return new ChannelDecoder(LISTENERS, input);
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java
deleted file mode 100644
index ff3c6d5..0000000
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/ConformanceTest.java
+++ /dev/null
@@ -1,199 +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.storage.netcdf;
-
-import java.util.Map;
-import java.io.IOException;
-import ucar.nc2.NetcdfFile;
-import org.opengis.metadata.Metadata;
-import org.opengis.metadata.citation.Role;
-import org.opengis.metadata.extent.TemporalExtent;
-import org.opengis.metadata.identification.DataIdentification;
-import org.opengis.metadata.maintenance.ScopeCode;
-import org.opengis.wrapper.netcdf.NetcdfMetadataTest;
-import org.apache.sis.metadata.iso.DefaultMetadataScope;
-import org.apache.sis.internal.netcdf.Decoder;
-import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
-import org.apache.sis.internal.netcdf.TestCase;
-import org.apache.sis.test.DependsOn;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-
-/**
- * Tests {@link MetadataReader} by inheriting the tests defined in the {@code geoapi-netcdf} module.
- * The tests are overridden in order to add some additional assertions for attributes not parsed by
- * the GeoAPI demo code.
- *
- * <p>This tests uses the UCAR implementation for reading NetCDF attributes.
- * For a test using the SIS embedded implementation, see {@link MetadataReaderTest}.</p>
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @since   0.3
- * @version 0.3
- * @module
- */
-@DependsOn(MetadataReaderTest.class)
-public final strictfp class ConformanceTest extends NetcdfMetadataTest {
-    /**
-     * Reads a metadata object from the given NetCDF file.
-     * This method is invoked by the tests inherited from the {@code geoapi-test} module.
-     *
-     * <div class="note"><b>Note:</b>
-     * The method name is "{@code wrap}" because the GeoAPI implementation maps the metadata methods to
-     * {@code NetcdfFile.findAttribute(String)} method calls. However in SIS implementation, the metadata
-     * object is fully created right at this method invocation time.</div>
-     *
-     * @param  file The NetCDF file to wrap.
-     * @return A metadata implementation created from the attributes found in the given file.
-     * @throws IOException If an error occurred while reading the given NetCDF file.
-     */
-    @Override
-    protected Metadata wrap(final NetcdfFile file) throws IOException {
-        final Decoder decoder = new DecoderWrapper(TestCase.LISTENERS, file);
-        final MetadataReader ncISO = new MetadataReader(decoder);
-        return ncISO.read();
-        // Do not close the file, as this will be done by the parent test class.
-    }
-
-    /**
-     * Asserts that the given map is empty.
-     */
-    private static void assertEmpty(final Map<?,?> map) {
-        if (!map.isEmpty()) {
-            fail(map.toString());
-        }
-    }
-
-    /**
-     * Adds a set of common property values expected by every tests in this class.
-     *
-     * @param expected   The map where to add additional attributes expected by the test.
-     * @param hasContact {@code true} for adding contact information.
-     */
-    private static void addCommonProperties(final Map<String,Object> expected, final boolean hasContact) {
-        assertNull(expected.put("metadataStandardName", "Geographic Information — Metadata Part 1: Fundamentals"));
-        assertNull(expected.put("metadataStandardVersion", "ISO 19115-1:2014(E)"));
-        if (hasContact) {
-            assertNull(expected.put("identificationInfo.pointOfContact.role", Role.POINT_OF_CONTACT));
-            assertNull(expected.put("contact.role", Role.POINT_OF_CONTACT));
-        }
-    }
-
-    /**
-     * Tests a file that contains THREDDS metadata. This method inherits the tests defined in GeoAPI,
-     * and adds some additional tests for attributes parsed by SIS but not by GeoAPI.
-     *
-     * @throws IOException If the test file can not be read.
-     */
-    @Test
-    @Override
-    public void testTHREDDS() throws IOException {
-        final Map<String,Object> expected = expectedProperties;
-        addCommonProperties(expected, true);
-        assertNull(expected.put("identificationInfo.citation.title",           "crm_v1.grd"));
-        assertNull(expected.put("identificationInfo.citation.identifier.code", "crm_v1"));
-        assertNull(expected.put("contentInfo.dimension.sequenceIdentifier",    "z"));
-        super.testTHREDDS();
-        assertArrayEquals("metadataScopes", new DefaultMetadataScope[] {
-                new DefaultMetadataScope(ScopeCode.DATASET, null),
-                new DefaultMetadataScope(ScopeCode.SERVICE, "http://localhost:8080//thredds/wms/crm/crm_vol9.nc"),
-                new DefaultMetadataScope(ScopeCode.SERVICE, "http://localhost:8080//thredds/wcs/crm/crm_vol9.nc")},
-                metadata.getMetadataScopes().toArray());
-        /*
-         * In the SIS case, the Metadata/Contact and Metadata/Identification/PointOfContact
-         * proprties are not just equals - they are expected to be the exact same instance.
-         */
-        assertSame("identificationInfo.pointOfContact", getSingleton(metadata.getContacts()),
-                getSingleton(getSingleton(metadata.getIdentificationInfo()).getPointOfContacts()));
-        /*
-         * Properties have been removed from the map as they were processed.
-         * Since expect every properties to have been processed, the maps should be empty by now.
-         */
-        assertEmpty(expectedProperties);
-        assertEmpty(actualProperties);
-    }
-
-    /**
-     * Tests a NetCDF binary file. This method inherits the tests defined in GeoAPI,
-     * and adds some additional tests for attributes parsed by SIS but not GeoAPI.
-     *
-     * @throws IOException If the test file can not be read.
-     */
-    @Test
-    @Override
-    public void testNCEP() throws IOException {
-        addCommonProperties(expectedProperties, true);
-        super.testNCEP();
-        assertSame("metadataScope", ScopeCode.DATASET, getSingleton(metadata.getMetadataScopes()).getResourceScope());
-        /*
-         * In the SIS case, the Metadata/Contact and Metadata/Identification/PointOfContact
-         * proprties are not just equals - they are expected to be the exact same instance.
-         */
-        assertSame("identificationInfo.pointOfContact", getSingleton(metadata.getContacts()),
-                getSingleton(getSingleton(metadata.getIdentificationInfo()).getPointOfContacts()));
-        /*
-         * Metadata / Data Identification / Temporal Extent.
-         */
-        final DataIdentification identification = (DataIdentification) getSingleton(metadata.getIdentificationInfo());
-        final TemporalExtent text = getSingleton(getSingleton(identification.getExtents()).getTemporalElements());
-        // Can not test at this time, since it requires the sis-temporal module (TODO).
-
-// TODO assertEmpty(expectedProperties);
-        assertEmpty(actualProperties);
-    }
-
-    /**
-     * Tests the Landsat file (binary format).
-     *
-     * @throws IOException If the test file can not be read.
-     */
-    @Test
-    @Override
-    public void testLandsat() throws IOException {
-        addCommonProperties(expectedProperties, false);
-        super.testLandsat();
-        assertSame("metadataScope", ScopeCode.DATASET, getSingleton(metadata.getMetadataScopes()).getResourceScope());
-
-        assertEmpty(expectedProperties);
-        assertEmpty(actualProperties);
-    }
-
-    /**
-     * Tests the "Current Icing Product" file (binary format).
-     *
-     * @throws IOException If the test file can not be read.
-     */
-    @Test
-    @Override
-    public void testCIP() throws IOException {
-        final Map<String,Object> expected = expectedProperties;
-        addCommonProperties(expected, true);
-        super.testCIP();
-        assertSame("metadataScope", ScopeCode.DATASET, getSingleton(metadata.getMetadataScopes()).getResourceScope());
-        /*
-         * In the SIS case, the Metadata/Contact and Metadata/Identification/PointOfContact
-         * proprties are not just equals - they are expected to be the exact same instance.
-         */
-        assertSame("identificationInfo.pointOfContact", getSingleton(metadata.getContacts()),
-                getSingleton(getSingleton(metadata.getIdentificationInfo()).getPointOfContacts()));
-
-// TODO assertEmpty(expectedProperties);
-        assertEmpty(actualProperties);
-    }
-}
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
index 88e0213..be7568f 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
@@ -19,9 +19,9 @@
 import java.io.IOException;
 import ucar.nc2.dataset.NetcdfDataset;
 import org.opengis.metadata.Metadata;
-import org.opengis.wrapper.netcdf.IOTestCase;
 import org.apache.sis.internal.netcdf.TestCase;
 import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.netcdf.IOTestCase;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.netcdf.impl.ChannelDecoderTest;
 import org.apache.sis.metadata.iso.DefaultMetadata;
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
index b17bcc0..c55f23e 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
@@ -18,7 +18,7 @@
 
 import java.io.IOException;
 import ucar.nc2.NetcdfFile;
-import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.IOTestCase;
 import org.apache.sis.internal.netcdf.TestCase;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
@@ -54,7 +54,7 @@
      */
     @Test
     public void testProbeContentFromStream() throws DataStoreException {
-        final StorageConnector c = new StorageConnector(IOTestCase.class.getResourceAsStream(NCEP));
+        final StorageConnector c = new StorageConnector(IOTestCase.getResourceAsStream(NCEP));
         final NetcdfStoreProvider provider = new NetcdfStoreProvider();
         final ProbeResult probe = provider.probeContent(c);
         assertTrue  ("isSupported", probe.isSupported());
@@ -90,7 +90,7 @@
      */
     @Test
     public void testDecoderFromStream() throws IOException, DataStoreException {
-        final StorageConnector c = new StorageConnector(IOTestCase.class.getResourceAsStream(NCEP));
+        final StorageConnector c = new StorageConnector(IOTestCase.getResourceAsStream(NCEP));
         final Decoder decoder = NetcdfStoreProvider.decoder(TestCase.LISTENERS, c);
         assertInstanceOf(NCEP, ChannelDecoder.class, decoder);
         decoder.close();
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
index 368addd..c772714 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
@@ -17,7 +17,7 @@
 package org.apache.sis.storage.netcdf;
 
 import org.opengis.metadata.Metadata;
-import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.IOTestCase;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.test.DependsOn;
@@ -46,7 +46,7 @@
      * @throws DataStoreException If an error occurred while reading the NetCDF file.
      */
     private static NetcdfStore create(final String dataset) throws DataStoreException {
-        return new NetcdfStore(new StorageConnector(IOTestCase.class.getResource(dataset)));
+        return new NetcdfStore(new StorageConnector(IOTestCase.getResource(dataset)));
     }
 
     /**
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java b/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java
index a97d5c8..4e16feb 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.test.suite;
 
-import org.opengis.wrapper.netcdf.IOTestCase;
+import org.apache.sis.internal.netcdf.IOTestCase;
 import org.apache.sis.test.TestSuite;
 import org.apache.sis.test.TestCase;
 import org.junit.runners.Suite;
@@ -40,7 +40,6 @@
     org.apache.sis.internal.netcdf.impl.VariableInfoTest.class,
     org.apache.sis.internal.netcdf.impl.GridGeometryInfoTest.class,
     org.apache.sis.storage.netcdf.MetadataReaderTest.class,
-    org.apache.sis.storage.netcdf.ConformanceTest.class,
     org.apache.sis.storage.netcdf.NetcdfStoreProviderTest.class,
     org.apache.sis.storage.netcdf.NetcdfStoreTest.class
 })
diff --git a/storage/sis-shapefile/pom.xml b/storage/sis-shapefile/pom.xml
index a67316b..b3e3c9f 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/ShapefileByteReader.java b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/ShapefileByteReader.java
index 5b1e663..0d80dfa 100644
--- a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/ShapefileByteReader.java
+++ b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/ShapefileByteReader.java
@@ -30,8 +30,8 @@
 import org.apache.sis.internal.shapefile.jdbc.*;
 import org.apache.sis.storage.shapefile.InvalidShapefileFormatException;
 import org.apache.sis.storage.shapefile.ShapeTypeEnum;
+import org.apache.sis.feature.AbstractFeature;
 import org.apache.sis.util.logging.Logging;
-import org.opengis.feature.Feature;
 
 import com.esri.core.geometry.*;
 
@@ -266,7 +266,7 @@
      * @param feature Feature to complete.
      * @throws InvalidShapefileFormatException if a validation problem occurs.
      */
-    public void completeFeature(Feature feature) throws InvalidShapefileFormatException {
+    public void completeFeature(AbstractFeature feature) throws InvalidShapefileFormatException {
         // insert points into some type of list
         int RecordNumber = getByteBuffer().getInt();
         @SuppressWarnings("unused")
@@ -304,7 +304,7 @@
      * Load point feature.
      * @param feature Feature to fill.
      */
-    private void loadPointFeature(Feature feature) {
+    private void loadPointFeature(AbstractFeature feature) {
         double x = getByteBuffer().getDouble();
         double y = getByteBuffer().getDouble();
         Point pnt = new Point(x, y);
@@ -315,7 +315,7 @@
      * Load polygon feature.
      * @param feature Feature to fill.
      */
-    private void loadPolygonFeature(Feature feature) {
+    private void loadPolygonFeature(AbstractFeature feature) {
         /* double xmin = */getByteBuffer().getDouble();
         /* double ymin = */getByteBuffer().getDouble();
         /* double xmax = */getByteBuffer().getDouble();
@@ -353,7 +353,6 @@
     @Deprecated // As soon as the readMultiplePolygonParts method proofs working well, this readUniquePolygonPart method can be removed and all calls be deferred to readMultiplePolygonParts.
     private Polygon readUniquePolygonPart(int numPoints) {
         /*int part = */ getByteBuffer().getInt();
-
         Polygon poly = new Polygon();
 
         // create a line from the points
@@ -437,7 +436,7 @@
      * Load polyline feature.
      * @param feature Feature to fill.
      */
-    private void loadPolylineFeature(Feature feature) {
+    private void loadPolylineFeature(AbstractFeature feature) {
         /* double xmin = */getByteBuffer().getDouble();
         /* double ymin = */getByteBuffer().getDouble();
         /* double xmax = */getByteBuffer().getDouble();
diff --git a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/Dbase3ByteReader.java b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/Dbase3ByteReader.java
index 1374c85..d9fecf9 100644
--- a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/Dbase3ByteReader.java
+++ b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/Dbase3ByteReader.java
@@ -24,7 +24,7 @@
 
 import org.apache.sis.internal.shapefile.jdbc.resultset.SQLIllegalColumnIndexException;
 import org.apache.sis.internal.shapefile.jdbc.resultset.SQLNoSuchFieldException;
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
 
 /**
  * Database byte reader contract. Used to allow refactoring of core byte management of a DBase file.
@@ -114,7 +114,7 @@
      * Load a row into a feature.
      * @param feature Feature to fill.
      */
-    public void loadRowIntoFeature(Feature feature);
+    public void loadRowIntoFeature(AbstractFeature feature);
 
     /**
      * Checks if a next row is available. Warning : it may be a deleted one.
diff --git a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/MappedByteReader.java b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/MappedByteReader.java
index 64c03f1..cb8b663 100644
--- a/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/MappedByteReader.java
+++ b/storage/sis-shapefile/src/main/java/org/apache/sis/internal/shapefile/jdbc/MappedByteReader.java
@@ -26,7 +26,7 @@
 
 import org.apache.sis.internal.shapefile.jdbc.resultset.SQLIllegalColumnIndexException;
 import org.apache.sis.internal.shapefile.jdbc.resultset.SQLNoSuchFieldException;
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.JDK8;
@@ -75,7 +75,7 @@
      * Load a row into a feature.
      * @param feature Feature to fill.
      */
-    @Override public void loadRowIntoFeature(Feature feature) {
+    @Override public void loadRowIntoFeature(AbstractFeature feature) {
         // TODO: ignore deleted records
         getByteBuffer().get(); // denotes whether deleted or current
         // read first part of record
diff --git a/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/InputFeatureStream.java b/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/InputFeatureStream.java
index 35eebc0..bd8404d 100644
--- a/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/InputFeatureStream.java
+++ b/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/InputFeatureStream.java
@@ -38,7 +38,7 @@
 import org.apache.sis.internal.shapefile.jdbc.statement.DBFStatement;
 import org.apache.sis.storage.DataStoreClosedException;
 import org.apache.sis.util.logging.Logging;
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
 
 /**
  * Input Stream of features.
@@ -211,7 +211,7 @@
      * @throws DataStoreQueryResultException if the shapefile results cause a trouble (wrong format, for example).
      * @throws InvalidShapefileFormatException if the shapefile structure shows a problem.
      */
-    public Feature readFeature() throws DataStoreClosedException, DataStoreQueryException, DataStoreQueryResultException, InvalidShapefileFormatException {
+    public AbstractFeature readFeature() throws DataStoreClosedException, DataStoreQueryException, DataStoreQueryResultException, InvalidShapefileFormatException {
         try {
             return internalReadFeature();
         }
@@ -275,7 +275,7 @@
      * @throws InvalidShapefileFormatException if the shapefile format is invalid.
      * @throws SQLNoDirectAccessAvailableException if the underlying SQL statement requires a direct access in the shapefile, but the shapefile cannot allow it.
      */
-    private Feature internalReadFeature() throws SQLConnectionClosedException, SQLInvalidStatementException, SQLIllegalParameterException, SQLNoSuchFieldException, SQLUnsupportedParsingFeatureException, SQLNotNumericException, SQLNotDateException, SQLFeatureNotSupportedException, InvalidShapefileFormatException, SQLNoDirectAccessAvailableException {
+    private AbstractFeature internalReadFeature() throws SQLConnectionClosedException, SQLInvalidStatementException, SQLIllegalParameterException, SQLNoSuchFieldException, SQLUnsupportedParsingFeatureException, SQLNotNumericException, SQLNotDateException, SQLFeatureNotSupportedException, InvalidShapefileFormatException, SQLNoDirectAccessAvailableException {
         try {
             if (this.endOfFile) {
                 return null;
@@ -314,7 +314,7 @@
                 }
             }
 
-            Feature feature = this.featuresType.newInstance();
+            AbstractFeature feature = this.featuresType.newInstance();
             this.shapefileReader.completeFeature(feature);
             DBFDatabaseMetaData metadata = (DBFDatabaseMetaData)this.connection.getMetaData();
 
diff --git a/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java b/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java
index aa02097..6255c26 100644
--- a/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java
+++ b/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java
@@ -28,7 +28,8 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.AbstractAttribute;
 
 
 /**
@@ -116,13 +117,13 @@
      @Test @Ignore // TODO Adapt with another shapefile.
      public void testHandleEofNotification() throws URISyntaxException, DataStoreException {
          ShapeFile shp = new ShapeFile(path("DEPARTEMENT.SHP"));
-         Feature first = null, last = null;
+         AbstractFeature first = null, last = null;
 
          Logger log = org.apache.sis.util.logging.Logging.getLogger(ShapeFileTest.class.getName());
 
          InputFeatureStream is = shp.findAll();
          try {
-             Feature feature = is.readFeature();
+             AbstractFeature feature = is.readFeature();
 
              // Read and retain the first and the last feature.
              while(feature != null) {
@@ -131,7 +132,7 @@
                  }
 
                  // Advice : To debug just before the last record, put a conditional breakpoint on department name "MEURTHE-ET-MOSELLE".
-                 String deptName = (String)feature.getProperty("NOM_DEPT").getValue();
+                 String deptName = (String)((AbstractAttribute) feature.getProperty("NOM_DEPT")).getValue();
                  log.info(deptName);
 
                  last = feature;
@@ -143,8 +144,8 @@
 
          assertNotNull("No record has been found in the DBase file or Shapefile.", first);
          assertNotNull("This test is not working well : last feature should always be set if any feature has been found.", last);
-         assertEquals("The first record red must be JURA department.", "JURA", first.getProperty("NOM_DEPT").getValue());
-         assertEquals("The last record red must be DEUX-SEVRES department.", "DEUX-SEVRES", last.getProperty("NOM_DEPT").getValue());
+         assertEquals("The first record red must be JURA department.", "JURA", ((AbstractAttribute) first.getProperty("NOM_DEPT")).getValue());
+         assertEquals("The last record red must be DEUX-SEVRES department.", "DEUX-SEVRES", ((AbstractAttribute) last.getProperty("NOM_DEPT")).getValue());
      }
 
      /**
@@ -157,7 +158,7 @@
          ShapeFile shp = new ShapeFile(path("ABRALicenseePt_4326_clipped.shp"));
 
          // 1) Find the third record, sequentially.
-         Feature thirdFeature;
+         AbstractFeature thirdFeature;
 
          InputFeatureStream isSequential = shp.findAll();
          try {
@@ -169,12 +170,12 @@
          }
 
          // Take one of its key fields and another field for reference, and its geometry.
-         Double sequentialAddressId = Double.valueOf((String)(thirdFeature.getProperty("ADDRID")).getValue());
-         String sequentialAddress = (String)(thirdFeature.getProperty("ADDRESS")).getValue();
+         Double sequentialAddressId = Double.valueOf((String)(((AbstractAttribute) thirdFeature.getProperty("ADDRID"))).getValue());
+         String sequentialAddress = (String)(((AbstractAttribute) thirdFeature.getProperty("ADDRESS"))).getValue();
          Object sequentialGeometry = thirdFeature.getPropertyValue("geometry");
 
          // 2) Now attempt a direct access to this feature.
-         Feature directFeature;
+         AbstractFeature directFeature;
          String sql = MessageFormat.format("SELECT * FROM ABRALicenseePt_4326_clipped WHERE ADDRID = {0,number,#0}", sequentialAddressId);
 
          InputFeatureStream isDirect = shp.find(sql);
@@ -187,8 +188,8 @@
 
          assertNotNull("The field ADDRID in the direct access feature has not been found again.", directFeature.getProperty("ADDRID"));
 
-         Double directAddressId = Double.valueOf((String)(directFeature.getProperty("ADDRID")).getValue());
-         String directAddress = (String)(directFeature.getProperty("ADDRESS")).getValue();
+         Double directAddressId = Double.valueOf((String)(((AbstractAttribute) directFeature.getProperty("ADDRID"))).getValue());
+         String directAddress = (String)(((AbstractAttribute) directFeature.getProperty("ADDRESS"))).getValue();
          Object directGeometry = directFeature.getPropertyValue("geometry");
 
          assertEquals("DBase part : direct access didn't returned the same address id than sequential access.", sequentialAddressId, directAddressId);
@@ -204,7 +205,7 @@
     private void readAll(ShapeFile shp) throws DataStoreException {
         InputFeatureStream is = shp.findAll();
         try {
-            Feature feature = is.readFeature();
+            AbstractFeature feature = is.readFeature();
 
             while(feature != null) {
                 feature = is.readFeature();
diff --git a/storage/sis-storage/pom.xml b/storage/sis-storage/pom.xml
index c0d55ba..3c738b4 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>0.8-jdk6-SNAPSHOT</version>
+    <version>0.8-SNAPSHOT</version>
   </parent>
 
 
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
index 6906ba0..b1814e4 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
@@ -58,10 +58,8 @@
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.Instant;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.AttributeType;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.AbstractIdentifiedType;
 
 
 /**
@@ -135,14 +133,14 @@
      *
      * @see #parseFeatureType(List)
      */
-    private final FeatureType featureType;
+    private final DefaultFeatureType featureType;
 
     /**
      * The features created while parsing the CSV file.
      *
      * @todo We should not keep them in memory, but instead use some kind of iterator or stream.
      */
-    private final List<Feature> features;
+    private final List<AbstractFeature> features;
 
     /**
      * {@code true} if {@link #featureType} contains a trajectory column.
@@ -178,9 +176,9 @@
             throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, name));
         }
         source = (r instanceof BufferedReader) ? (BufferedReader) r : new LineNumberReader(r);
-        GeneralEnvelope envelope    = null;
-        FeatureType     featureType = null;
-        Foliation       foliation   = null;
+        GeneralEnvelope envelope = null;
+        DefaultFeatureType featureType = null;
+        Foliation foliation = null;
         try {
             final List<String> elements = new ArrayList<String>();
             source.mark(1024);
@@ -234,7 +232,7 @@
         this.featureType = featureType;
         this.foliation   = foliation;
         this.metadata    = MetadataHelper.createForTextFile(connector);
-        this.features    = new ArrayList<Feature>();
+        this.features    = new ArrayList<AbstractFeature>();
     }
 
     /**
@@ -370,9 +368,9 @@
      * @param  elements The line elements. The first elements should be {@code "@columns"}.
      * @return The column metadata, or {@code null} if the given list does not contain enough elements.
      */
-    private FeatureType parseFeatureType(final List<String> elements) throws DataStoreException {
+    private DefaultFeatureType parseFeatureType(final List<String> elements) throws DataStoreException {
         final int size = elements.size();
-        final List<PropertyType> properties = new ArrayList<PropertyType>();
+        final List<AbstractIdentifiedType> properties = new ArrayList<AbstractIdentifiedType>();
         for (int i=1; i<size; i++) {
             final String name = elements.get(i);
             Class<?> type = null;
@@ -432,13 +430,13 @@
             properties.add(createProperty(name, type, minOccurrence));
         }
         return new DefaultFeatureType(Collections.singletonMap(DefaultFeatureType.NAME_KEY, name),
-                false, null, properties.toArray(new PropertyType[properties.size()]));
+                false, null, properties.toArray(new AbstractIdentifiedType[properties.size()]));
     }
 
     /**
      * Creates a property type for the given name and type.
      */
-    private static PropertyType createProperty(final String name, final Class<?> type, final int minOccurrence) {
+    private static AbstractIdentifiedType createProperty(final String name, final Class<?> type, final int minOccurrence) {
         return new DefaultAttributeType(Collections.singletonMap(DefaultAttributeType.NAME_KEY, name), type, minOccurrence, 1, null);
     }
 
@@ -490,23 +488,23 @@
      * @throws DataStoreException if an error occurred while creating the iterator.
      */
     @SuppressWarnings({"unchecked", "rawtypes", "fallthrough"})
-    public Iterator<Feature> getFeatures() throws DataStoreException {
+    public Iterator<AbstractFeature> getFeatures() throws DataStoreException {
         if (features.isEmpty()) try {
-            final Collection<? extends PropertyType> properties = featureType.getProperties(false);
+            final Collection<? extends AbstractIdentifiedType> properties = featureType.getProperties(false);
             final ObjectConverter<String,?>[] converters = new ObjectConverter[properties.size()];
             final String[]     propertyNames   = new String[converters.length];
             final boolean      hasTrajectories = this.hasTrajectories;
             final TimeEncoding timeEncoding    = this.timeEncoding;
             final List<String> values          = new ArrayList<String>();
             int i = -1;
-            for (final PropertyType p : properties) {
+            for (final AbstractIdentifiedType p : properties) {
                 propertyNames[++i] = p.getName().tip().toString();
                 switch (i) {    // This switch shall follow the same cases than the swith in the loop.
                     case 1:
                     case 2: if (timeEncoding != null) continue;     // else fall through
                     case 3: if (hasTrajectories) continue;
                 }
-                converters[i] = ObjectConverters.find(String.class, ((AttributeType) p).getValueClass());
+                converters[i] = ObjectConverters.find(String.class, ((DefaultAttributeType) p).getValueClass());
             }
             /*
              * Above lines prepared the constants. Now parse all lines.
@@ -517,7 +515,7 @@
                 split(line, values);
                 final int length = Math.min(propertyNames.length, values.size());
                 if (length != 0) {
-                    final Feature feature = featureType.newInstance();
+                    final AbstractFeature feature = featureType.newInstance();
                     for (i=0; i<length; i++) {
                         final String text = values.get(i);
                         final String name = propertyNames[i];
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
index 2383d23..dd3a05a 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
@@ -30,7 +30,9 @@
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
 // Branch-dependent imports
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.metadata.iso.extent.DefaultSpatialTemporalExtent;
+import org.apache.sis.metadata.iso.identification.AbstractIdentification;
 
 
 /**
@@ -69,14 +71,14 @@
         } finally {
             store.close();
         }
-        final SpatialTemporalExtent extent = (SpatialTemporalExtent) getSingleton(getSingleton(getSingleton(
-                metadata.getIdentificationInfo()).getExtents()).getTemporalElements());
+        final AbstractIdentification id = (AbstractIdentification) getSingleton(metadata.getIdentificationInfo());
+        final SpatialTemporalExtent extent = (SpatialTemporalExtent) getSingleton(getSingleton(id.getExtents()).getTemporalElements());
         final GeographicBoundingBox bbox = (GeographicBoundingBox) getSingleton(extent.getSpatialExtent());
         assertEquals("westBoundLongitude", 50.23, bbox.getWestBoundLongitude(), STRICT);
         assertEquals("eastBoundLongitude", 50.31, bbox.getEastBoundLongitude(), STRICT);
         assertEquals("southBoundLatitude",  9.23, bbox.getSouthBoundLatitude(), STRICT);
         assertEquals("northBoundLatitude",  9.27, bbox.getNorthBoundLatitude(), STRICT);
-        assertNull("Should not have a vertical extent.", extent.getVerticalExtent());
+        assertNull("Should not have a vertical extent.", ((DefaultSpatialTemporalExtent) extent).getVerticalExtent());
         assertNotNull("Should have a temporal extent", extent.getExtent());
     }
 
@@ -89,7 +91,7 @@
     public void testGetFeatures() throws DataStoreException {
         Store store = new Store(new StorageConnector(new StringReader(TEST_DATA)));
         try {
-            final Iterator<Feature> it = store.getFeatures();
+            final Iterator<AbstractFeature> it = store.getFeatures();
             assertFeatureEquals(it.next(), "a", new double[] {11, 2, 12, 3},        "walking", 1);
             assertFeatureEquals(it.next(), "b", new double[] {10, 2, 11, 3},        "walking", 2);
             assertFeatureEquals(it.next(), "a", new double[] {12, 3, 10, 3},        "walking", 2);
@@ -103,7 +105,7 @@
     /**
      * Asserts that the given feature has the given properties.
      */
-    private static void assertFeatureEquals(final Feature f, final String mfidref,
+    private static void assertFeatureEquals(final AbstractFeature f, final String mfidref,
             final double[] trajectory, final String state, final int typeCode)
     {
         assertEquals     ("mfidref",    mfidref,  f.getPropertyValue("mfidref"));
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/wkt/StoreTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/wkt/StoreTest.java
index 71366a3..35c8fc7 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/wkt/StoreTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/wkt/StoreTest.java
@@ -28,7 +28,7 @@
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.StandardCharsets;
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/StoreTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/StoreTest.java
index 9effc7f..86041d9 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/StoreTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/xml/StoreTest.java
@@ -20,6 +20,7 @@
 import java.io.StringReader;
 import org.opengis.metadata.Metadata;
 import org.opengis.metadata.citation.*;
+import org.opengis.metadata.identification.CharacterSet;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
@@ -30,9 +31,6 @@
 import static org.opengis.test.Assert.*;
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
-// Branch-dependent imports
-import org.apache.sis.internal.jdk7.StandardCharsets;
-
 
 /**
  * Tests {@link Store}.
@@ -100,16 +98,14 @@
         } finally {
             store.close();
         }
-        final Responsibility resp     = getSingleton(metadata.getContacts());
-        final Party          party    = getSingleton(resp.getParties());
-        final Contact        contact  = getSingleton(party.getContactInfo());
-        final OnlineResource resource = getSingleton(contact.getOnlineResources());
+        final ResponsibleParty resp     = getSingleton(metadata.getContacts());
+        final Contact          contact  = resp.getContactInfo();
+        final OnlineResource   resource = contact.getOnlineResource();
 
-        assertInstanceOf("party", Organisation.class, party);
-        assertEquals(Locale.ENGLISH,              getSingleton(metadata.getLanguages()));
-        assertEquals(StandardCharsets.UTF_8,      getSingleton(metadata.getCharacterSets()));
+        assertEquals(Locale.ENGLISH,              metadata.getLanguage());
+        assertEquals(CharacterSet.UTF_8,          metadata.getCharacterSet());
         assertEquals(Role.PRINCIPAL_INVESTIGATOR, resp.getRole());
-        assertEquals("Apache SIS",                String.valueOf(party.getName()));
+        assertEquals("Apache SIS",                String.valueOf(resp.getOrganisationName()));
         assertEquals("http://sis.apache.org",     String.valueOf(resource.getLinkage()));
         assertEquals(OnLineFunction.INFORMATION,  resource.getFunction());
     }