diff --git a/src/Metadata/CachingMetadataFactory.php b/src/Metadata/CachingMetadataFactory.php
index 35f553f2eec8ba76c06abd80f66dc5a468ef404d..13cdec961e774be0b1a76236aaf470ae855d2a15 100644
--- a/src/Metadata/CachingMetadataFactory.php
+++ b/src/Metadata/CachingMetadataFactory.php
@@ -21,7 +21,7 @@ namespace Irstea\NgModelGeneratorBundle\Metadata;
 
 use Doctrine\Common\Cache\ArrayCache;
 use Doctrine\Common\Cache\Cache;
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Class CachingMetadataFactory.
@@ -49,7 +49,7 @@ final class CachingMetadataFactory implements MetadataFactoryInterface
     /**
      * {@inheritdoc}
      */
-    public function isResource(PHPClass $class): bool
+    public function isResource(ClassName $class): bool
     {
         return $this->inner->isResource($class);
     }
@@ -57,7 +57,7 @@ final class CachingMetadataFactory implements MetadataFactoryInterface
     /**
      * {@inheritdoc}
      */
-    public function getResourceMetadata(PHPClass $class): ResourceMetadata
+    public function getResourceMetadata(ClassName $class): ResourceMetadata
     {
         return $this->memoize(__METHOD__, $class->getFullName(), function () use ($class) {
             return $this->inner->getResourceMetadata($class);
diff --git a/src/Metadata/ClassHierarchy.php b/src/Metadata/ClassHierarchy.php
index 743cb650147634d1b50943e7e61baa0dad868555..8f1b536c30570dfef375d27f72558251b11e278f 100644
--- a/src/Metadata/ClassHierarchy.php
+++ b/src/Metadata/ClassHierarchy.php
@@ -19,7 +19,7 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Interface ClassHierarchy.
@@ -27,16 +27,16 @@ use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 interface ClassHierarchy
 {
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
-     * @return PHPClass|null
+     * @return ClassName|null
      */
-    public function getParent(PHPClass $class): ?PHPClass;
+    public function getParent(ClassName $class): ?ClassName;
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
-     * @return PHPClass[]
+     * @return ClassName[]
      */
-    public function getChildren(PHPClass $class): array;
+    public function getChildren(ClassName $class): array;
 }
diff --git a/src/Metadata/MetadataFactory.php b/src/Metadata/MetadataFactory.php
index b15e8dc6a5f29f18fc4b086a1c7bc041b8003715..8c2348525def988297efa52dd21a3bd55d23e1fa 100644
--- a/src/Metadata/MetadataFactory.php
+++ b/src/Metadata/MetadataFactory.php
@@ -30,6 +30,7 @@ use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
 use ApiPlatform\Core\Metadata\Resource\ResourceMetadata as APIResourceMetadata;
 use ApiPlatform\Core\PathResolver\OperationPathResolverInterface;
 use Doctrine\Common\Inflector\Inflector;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Psr\Container\ContainerInterface;
 use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
@@ -116,7 +117,7 @@ final class MetadataFactory implements MetadataFactoryInterface
     /**
      * {@inheritdoc}
      */
-    public function isResource(PHPClass $class): bool
+    public function isResource(ClassName $class): bool
     {
         return $this->resourceClassResolver->isResourceClass($class->getFullName());
     }
@@ -124,7 +125,7 @@ final class MetadataFactory implements MetadataFactoryInterface
     /**
      * {@inheritdoc}
      */
-    public function getResourceMetadata(PHPClass $class): ResourceMetadata
+    public function getResourceMetadata(ClassName $class): ResourceMetadata
     {
         $className = $class->getFullName();
         $metadata = $this->resourceMetadataFactory->create($className);
@@ -177,11 +178,11 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return OperationMetadata[]
      */
-    private function getOperations(PHPClass $class): array
+    private function getOperations(ClassName $class): array
     {
         $resourceMetadata = $this->resourceMetadataFactory->create($class->getFullName());
 
@@ -200,7 +201,7 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param APIResourceMetadata $resourceMetadata
      * @param string              $name
      * @param string              $type
@@ -209,7 +210,7 @@ final class MetadataFactory implements MetadataFactoryInterface
      * @return OperationMetadata
      */
     private function getOperation(
-        PHPClass $class,
+        ClassName $class,
         APIResourceMetadata $resourceMetadata,
         string $name,
         string $type,
@@ -279,12 +280,12 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param PHPClass $class
-     * @param array    $filterIds
+     * @param ClassName $class
+     * @param array     $filterIds
      *
      * @return FilterInterface[]
      */
-    private function getFilters(PHPClass $class, array $filterIds): array
+    private function getFilters(ClassName $class, array $filterIds): array
     {
         $filters = [];
 
@@ -307,7 +308,7 @@ final class MetadataFactory implements MetadataFactoryInterface
      * @parma string $operationName
      *
      * @param OperationDef|null $opDef
-     * @param PHPClass          $class
+     * @param ClassName         $class
      * @param bool              $normalization
      * @param string[]          $groups
      *
@@ -319,7 +320,7 @@ final class MetadataFactory implements MetadataFactoryInterface
      */
     private function getOperationSerialization(
         ?OperationDef $opDef,
-        PHPClass $class,
+        ClassName $class,
         bool $normalization,
         array $groups
     ): SerializationMetadata {
@@ -334,7 +335,7 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param PHPClass     $class
+     * @param ClassName    $class
      * @param bool         $normalization
      * @param OperationDef $opDef
      * @param string[]     $groups
@@ -345,7 +346,7 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @return SerializationMetadata
      */
-    private function doGetSerialization(PHPClass $class, bool $normalization, ?OperationDef $opDef, array $groups): SerializationMetadata
+    private function doGetSerialization(ClassName $class, bool $normalization, ?OperationDef $opDef, array $groups): SerializationMetadata
     {
         if ($normalization) {
             $metadata = $this->resourceMetadataFactory->create($class->getFullName());
@@ -374,25 +375,23 @@ final class MetadataFactory implements MetadataFactoryInterface
         /** @var RepresentationMetadata[] $reprs */
         $representations = [];
 
-        /** @var string[] $queue */
-        $queue = [$class->getFullName()];
+        /** @var ClassName[] $queue */
+        $queue = [$class];
 
         while ($queue) {
-            /** @var string $currentName */
-            $currentName = array_shift($queue);
-            $current = PHPClass::get($currentName);
+            $current = array_shift($queue);
 
-            if (isset($representations[$currentName]) || !$this->isResource($current)) {
+            if (isset($representations[$current->getFullName()]) || !$this->isResource($current)) {
                 continue;
             }
 
             $parent = $this->classHierarchy->getParent($current);
             if ($parent) {
-                $queue[] = $parent->getFullName();
+                $queue[] = $parent;
             }
 
             foreach ($this->classHierarchy->getChildren($current) as $children) {
-                $queue[] = $children->getFullName();
+                $queue[] = $children;
             }
 
             $propertiesMeta = $this->getPropertiesMeta($current, $groups);
@@ -406,20 +405,22 @@ final class MetadataFactory implements MetadataFactoryInterface
                 $properties[$propertyName] = $property;
                 $type = $property->getLeafType();
                 if ($type->getClassName()) {
-                    $queue[] = $type->getClassName();
+                    $queue[] = PHPClass::get($type->getClassName());
                 }
             }
 
-            $name = ($current->is($class) ? $selfNamePrefix : $otherNamePrefix) . $current->getBaseName();
+            $name = ($current === $class ? $selfNamePrefix : $otherNamePrefix) . $current->getBaseName();
 
-            $representations[$currentName] = new RepresentationMetadata($name, $current, $parent, $properties);
+            $abstract = (new \ReflectionClass($current->getFullName()))->isAbstract();
+
+            $representations[$current->getFullName()] = new RepresentationMetadata($name, $current, $parent, $properties, $abstract);
         }
 
         return new SerializationMetadata($class, $groups, $normalization, $representations);
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param string              $name
      * @param APIPropertyMetadata $property
      *
@@ -427,13 +428,13 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @internal
      */
-    public function filterGetProperty(PHPClass $class, string $name, APIPropertyMetadata $property): bool
+    public function filterGetProperty(ClassName $class, string $name, APIPropertyMetadata $property): bool
     {
         return $property->isIdentifier() || $property->isReadable() || $property->isReadableLink();
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param string              $name
      * @param APIPropertyMetadata $property
      *
@@ -441,13 +442,13 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @internal
      */
-    public function filterCreateProperty(PHPClass $class, string $name, APIPropertyMetadata $property): bool
+    public function filterCreateProperty(ClassName $class, string $name, APIPropertyMetadata $property): bool
     {
         return $property->isWritable() || $property->isWritableLink() || ($property->isInitializable() ?: false);
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param string              $name
      * @param APIPropertyMetadata $property
      *
@@ -455,13 +456,13 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @internal
      */
-    public function filterUpdateProperty(PHPClass $class, string $name, APIPropertyMetadata $property): bool
+    public function filterUpdateProperty(ClassName $class, string $name, APIPropertyMetadata $property): bool
     {
         return $this->filterGetProperty($class, $name, $property) || $property->isWritable() || $property->isWritableLink();
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param string              $name
      * @param APIPropertyMetadata $property
      *
@@ -469,21 +470,21 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @internal
      */
-    public function filterAnyProperty(PHPClass $class, string $name, APIPropertyMetadata $property): bool
+    public function filterAnyProperty(ClassName $class, string $name, APIPropertyMetadata $property): bool
     {
         return true;
     }
 
     /**
-     * @param PHPClass $class
-     * @param array    $groups
+     * @param ClassName $class
+     * @param array     $groups
      *
      * @throws \ApiPlatform\Core\Exception\PropertyNotFoundException
      * @throws \ApiPlatform\Core\Exception\ResourceClassNotFoundException
      *
      * @return APIPropertyMetadata[]
      */
-    private function getPropertiesMeta(PHPClass $class, array $groups): array
+    private function getPropertiesMeta(ClassName $class, array $groups): array
     {
         $properties = [];
         $options = $groups ? ['serializer_groups' => $groups] : [];
@@ -504,13 +505,13 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param PHPClass            $class
+     * @param ClassName           $class
      * @param string              $propertyName
      * @param APIPropertyMetadata $propertyMeta
      *
      * @return PropertyMetadata
      */
-    private function mapProperty(PHPClass $class, string $propertyName, APIPropertyMetadata $propertyMeta): PropertyMetadata
+    private function mapProperty(ClassName $class, string $propertyName, APIPropertyMetadata $propertyMeta): PropertyMetadata
     {
         $leafType = $typeMeta = $propertyMeta->getType();
 
diff --git a/src/Metadata/MetadataFactoryInterface.php b/src/Metadata/MetadataFactoryInterface.php
index 42dfa79f199d2b7122876dbd0f67ef977a28431f..00c45858a3d7ae83386bdd34016c9c3f42cd6956 100644
--- a/src/Metadata/MetadataFactoryInterface.php
+++ b/src/Metadata/MetadataFactoryInterface.php
@@ -19,7 +19,7 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Interface MetadataFactoryInterface.
@@ -27,18 +27,18 @@ use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 interface MetadataFactoryInterface
 {
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return bool
      */
-    public function isResource(PHPClass $class): bool;
+    public function isResource(ClassName $class): bool;
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return ResourceMetadata
      */
-    public function getResourceMetadata(PHPClass $class): ResourceMetadata;
+    public function getResourceMetadata(ClassName $class): ResourceMetadata;
 
     /**
      * @return PaginationMetadata
diff --git a/src/Metadata/RepresentationMetadata.php b/src/Metadata/RepresentationMetadata.php
index 6145b37550eba34822b212dc07a452c0b67dd62c..7aae54791e76103966026ce7ecbcf9ace3490921 100644
--- a/src/Metadata/RepresentationMetadata.php
+++ b/src/Metadata/RepresentationMetadata.php
@@ -19,12 +19,12 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Class RepresentationMetadata.
  */
-final class RepresentationMetadata implements \JsonSerializable
+final class RepresentationMetadata implements ClassName
 {
     /**
      * @var string
@@ -32,12 +32,12 @@ final class RepresentationMetadata implements \JsonSerializable
     private $name;
 
     /**
-     * @var PHPClass
+     * @var ClassName
      */
     private $class;
 
     /**
-     * @var null|PHPClass
+     * @var null|ClassName
      */
     private $parent;
 
@@ -50,11 +50,11 @@ final class RepresentationMetadata implements \JsonSerializable
      * RepresentationMetadata constructor.
      *
      * @param string             $name
-     * @param PHPClass           $class
-     * @param PHPClass|null      $parent
+     * @param ClassName          $class
+     * @param ClassName|null     $parent
      * @param PropertyMetadata[] $properties
      */
-    public function __construct(string $name, PHPClass $class, ?PHPClass $parent, array $properties)
+    public function __construct(string $name, ClassName $class, ?ClassName $parent, array $properties, bool $abstract)
     {
         $this->class = $class;
         $this->parent = $parent;
@@ -78,21 +78,43 @@ final class RepresentationMetadata implements \JsonSerializable
     }
 
     /**
-     * Get class.
-     *
-     * @return PHPClass
+     * {@inheritdoc}
+     */
+    public function getNamespace(): string
+    {
+        return $this->class->getNamespace();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBaseName(): string
+    {
+        return $this->class->getBaseName();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFullName(): string
+    {
+        return $this->class->getFullName();
+    }
+
+    /**
+     * {@inheritdoc}
      */
-    public function getClass(): PHPClass
+    public function __toString()
     {
-        return $this->class;
+        return $this->class->__toString();
     }
 
     /**
      * Get parent.
      *
-     * @return null|PHPClass
+     * @return null|ClassName
      */
-    public function getParent(): ?PHPClass
+    public function getParent(): ?ClassName
     {
         return $this->parent;
     }
diff --git a/src/Metadata/ResourceClassHierarchy.php b/src/Metadata/ResourceClassHierarchy.php
index e4bed6fefb279486fbc41fcefff1a251d6e0dae2..a751dcb64dc6e4cb17e90c3d15575cd16ce510ad 100644
--- a/src/Metadata/ResourceClassHierarchy.php
+++ b/src/Metadata/ResourceClassHierarchy.php
@@ -20,6 +20,7 @@
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
 use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 
 /**
@@ -27,10 +28,10 @@ use Irstea\NgModelGeneratorBundle\Models\PHPClass;
  */
 final class ResourceClassHierarchy implements ClassHierarchy
 {
-    /** @var PHPClass[] */
+    /** @var ClassName[] */
     private $parents = [];
 
-    /** @var PHPClass[][] */
+    /** @var ClassName[][] */
     private $children = [];
 
     /**
@@ -44,16 +45,16 @@ final class ResourceClassHierarchy implements ClassHierarchy
     }
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      */
-    private function preload(PHPClass $class): void
+    private function preload(ClassName $class): void
     {
         $className = $class->getFullName();
         if (\array_key_exists($className, $this->parents)) {
             return;
         }
 
-        $parent = $class->getReflection()->getParentClass();
+        $parent = new \ReflectionClass($class->getFullName());
         if (!$parent) {
             $this->parents[$className] = null;
 
@@ -72,7 +73,7 @@ final class ResourceClassHierarchy implements ClassHierarchy
     /**
      * {@inheritdoc}
      */
-    public function getParent(PHPClass $class): ?PHPClass
+    public function getParent(ClassName $class): ?ClassName
     {
         $this->preload($class);
 
@@ -82,7 +83,7 @@ final class ResourceClassHierarchy implements ClassHierarchy
     /**
      * {@inheritdoc}
      */
-    public function getChildren(PHPClass $class): array
+    public function getChildren(ClassName $class): array
     {
         $this->preload($class);
 
diff --git a/src/Metadata/ResourceMetadata.php b/src/Metadata/ResourceMetadata.php
index 628786ae6cdd8303ed57011b5c29ef466c46312c..6b53e5026c4969ab2409828a6b322d9e180f9ce3 100644
--- a/src/Metadata/ResourceMetadata.php
+++ b/src/Metadata/ResourceMetadata.php
@@ -19,17 +19,17 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Class ResourceMetadata.
  */
-class ResourceMetadata implements \JsonSerializable
+class ResourceMetadata implements ClassName
 {
-    /** @var PHPClass */
+    /** @var ClassName */
     private $class;
 
-    /** @var PHPClass|null */
+    /** @var ClassName|null */
     private $parentClass;
 
     /** @var string */
@@ -41,16 +41,14 @@ class ResourceMetadata implements \JsonSerializable
     /** @var OperationMetadata[] */
     private $operations = [];
 
-    /**
-     * @var SerializationMetadata
-     */
+    /** @var SerializationMetadata */
     private $defaultNormalization;
 
     /**
      * ResourceMetadata constructor.
      *
-     * @param PHPClass              $class
-     * @param PHPClass|null         $parentClass
+     * @param ClassName             $class
+     * @param ClassName|null        $parentClass
      * @param string                $shortName
      * @param string                $description
      * @param bool                  $abstract
@@ -58,8 +56,8 @@ class ResourceMetadata implements \JsonSerializable
      * @param OperationMetadata[]   $operations
      */
     public function __construct(
-        PHPClass $class,
-        ?PHPClass $parentClass,
+        ClassName $class,
+        ?ClassName $parentClass,
         string $shortName,
         string $description,
         bool $abstract,
@@ -79,31 +77,43 @@ class ResourceMetadata implements \JsonSerializable
     }
 
     /**
-     * Get className.
-     *
-     * @return string
+     * {@inheritdoc}
      */
-    public function getClassName(): string
+    public function getNamespace(): string
     {
-        return $this->class->getFullName();
+        return $this->class->getNamespace();
     }
 
     /**
-     * Get shortName.
-     *
-     * @return string
+     * {@inheritdoc}
      */
-    public function getShortName(): string
+    public function getBaseName(): string
     {
         return $this->class->getBaseName();
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getFullName(): string
+    {
+        return $this->class->getFullName();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString()
+    {
+        return $this->getFullName();
+    }
+
     /**
      * Get parentClass.
      *
-     * @return PHPClass|null
+     * @return ClassName|null
      */
-    public function getParentClass(): ?PHPClass
+    public function getParentClass(): ?ClassName
     {
         return $this->parentClass;
     }
@@ -138,16 +148,6 @@ class ResourceMetadata implements \JsonSerializable
         return $this->abstract;
     }
 
-    /**
-     * Get class.
-     *
-     * @return PHPClass
-     */
-    public function getClass(): PHPClass
-    {
-        return $this->class;
-    }
-
     /**
      * Get operations.
      *
diff --git a/src/Metadata/SerializationMetadata.php b/src/Metadata/SerializationMetadata.php
index e9a47e11fd19569457cf2d531e5aca74bd303f21..bd76426d0dbd1a67b946fbd5c2f1ec88de5ed164 100644
--- a/src/Metadata/SerializationMetadata.php
+++ b/src/Metadata/SerializationMetadata.php
@@ -19,42 +19,34 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 
 /**
  * Class SerializationMetadata.
  */
-final class SerializationMetadata implements \JsonSerializable
+final class SerializationMetadata implements ClassName
 {
-    /**
-     * @var PHPClass
-     */
+    /** @var ClassName */
     private $root;
 
-    /**
-     * @var string[]
-     */
+    /** @var string[] */
     private $groups;
 
-    /**
-     * @var bool
-     */
+    /** @var bool */
     private $normalization;
 
-    /**
-     * @var RepresentationMetadata[]
-     */
+    /** @var RepresentationMetadata[] */
     private $representations = [];
 
     /**
      * SerializationMetadata constructor.
      *
-     * @param PHPClass                 $root
+     * @param ClassName                $root
      * @param string[]                 $groups
      * @param bool                     $normalization
      * @param RepresentationMetadata[] $representations
      */
-    public function __construct(PHPClass $root, array $groups, bool $normalization, array $representations)
+    public function __construct(ClassName $root, array $groups, bool $normalization, array $representations)
     {
         $this->groups = $groups;
         sort($this->groups);
@@ -63,7 +55,7 @@ final class SerializationMetadata implements \JsonSerializable
         $this->normalization = $normalization;
 
         foreach ($representations as $representation) {
-            $this->representations[$representation->getClass()->getFullName()] = $representation;
+            $this->representations[$representation->getFullName()] = $representation;
         }
         ksort($this->representations);
     }
@@ -81,21 +73,43 @@ final class SerializationMetadata implements \JsonSerializable
     /**
      * Get root.
      *
-     * @return PHPClass
+     * @return ClassName
      */
-    public function getRoot(): PHPClass
+    public function getRoot(): ClassName
     {
         return $this->root;
     }
 
     /**
-     * @param PHPClass|string $class
-     *
-     * @return bool
+     * {@inheritdoc}
+     */
+    public function getNamespace(): string
+    {
+        return $this->root->getNamespace();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBaseName(): string
+    {
+        return $this->root->getBaseName();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFullName(): string
+    {
+        return $this->root->getFullName();
+    }
+
+    /**
+     * {@inheritdoc}
      */
-    public function isRoot($class): bool
+    public function __toString()
     {
-        return $this->root === PHPClass::get($class);
+        return $this->root->__toString();
     }
 
     /**
@@ -109,21 +123,21 @@ final class SerializationMetadata implements \JsonSerializable
     }
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return bool
      */
-    public function hasRepresentationOf(PHPClass $class): bool
+    public function hasRepresentationOf(ClassName $class): bool
     {
         return isset($this->representations[$class->getFullName()]);
     }
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return RepresentationMetadata
      */
-    public function getRepresentationOf(PHPClass $class): RepresentationMetadata
+    public function getRepresentationOf(ClassName $class): RepresentationMetadata
     {
         return $this->representations[$class->getFullName()];
     }
@@ -139,15 +153,15 @@ final class SerializationMetadata implements \JsonSerializable
     }
 
     /**
-     * @return PHPClass[]
+     * @return ClassName[]
      */
     public function getRootSubClasses(): array
     {
         $subclasses = [];
-        $rootClassName = $this->getRoot()->getFullName();
+        $rootClassName = $this->getFullName();
         foreach ($this->representations as $className => $meta) {
             if (\is_subclass_of($className, $rootClassName, true)) {
-                $subclasses[$className] = PHPClass::get($className);
+                $subclasses[$className] = $meta;
             }
         }
 
diff --git a/src/ModelGenerator.php b/src/ModelGenerator.php
index 4266323d4d9c37308d39fcf0a4e1ca7d57ee5215..03f5408295d782ceebc8f21bb74d21f306489b8e 100644
--- a/src/ModelGenerator.php
+++ b/src/ModelGenerator.php
@@ -26,6 +26,7 @@ use Irstea\NgModelGeneratorBundle\Exceptions\TypeError;
 use Irstea\NgModelGeneratorBundle\Iterators\IteratorBuilder;
 use Irstea\NgModelGeneratorBundle\Metadata\MetadataFactoryInterface;
 use Irstea\NgModelGeneratorBundle\Metadata\ResourceMetadata;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\Declaration;
 use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Irstea\NgModelGeneratorBundle\Models\Types\Alias;
@@ -271,11 +272,11 @@ final class ModelGenerator
         $repositories = [];
 
         /**
-         * @var PHPClass
+         * @var ClassName
          * @var ResourceMetadata $resourceMeta
          */
         foreach ($this->getResourceMetadata() as $class => $resourceMeta) {
-            $repoName = $resourceMeta->getShortName() . 'Repository';
+            $repoName = $resourceMeta->getBaseName() . 'Repository';
 
             try {
                 $repositories[$repoName] = $this->typeFactory->getOrCreate(
@@ -313,7 +314,7 @@ final class ModelGenerator
             throw new TypeError(
                 sprintf(
                     'No property found for %s (groups: [%s])',
-                    $resourceMeta->getShortName(),
+                    $resourceMeta->getBaseName(),
                     implode(', ', $defaultNormalization->getGroups())
                 )
             );
@@ -323,7 +324,7 @@ final class ModelGenerator
             throw new TypeError(
                 sprintf(
                     'No identifier found for %s (groups: [%s])',
-                    $resourceMeta->getShortName(),
+                    $resourceMeta->getBaseName(),
                     implode(', ', $defaultNormalization->getGroups())
                 )
             );
@@ -336,6 +337,6 @@ final class ModelGenerator
             $operations[] = $mapper();
         }
 
-        return new Repository($resourceMeta->getClass(), $defaultRepr, $identifier, $operations);
+        return new Repository($resourceMeta, $defaultRepr, $identifier, $operations);
     }
 }
diff --git a/src/Models/ClassInfo.php b/src/Models/ClassInfo.php
index 0d1ada9ea3a8076d181a15f6d449a39eaf76a50b..e317e8fbe78830fb73a0bd602844070b401eca7a 100644
--- a/src/Models/ClassInfo.php
+++ b/src/Models/ClassInfo.php
@@ -19,24 +19,24 @@
 
 namespace Irstea\NgModelGeneratorBundle\Models;
 
+use Irstea\NgModelGeneratorBundle\Exceptions\DomainException;
 use Irstea\NgModelGeneratorBundle\Metadata\PropertyMetadata;
-use Irstea\NgModelGeneratorBundle\Models\Types\Objects\Property;
 
 /**
  * Class ClassInfo.
  */
-final class ClassInfo implements \JsonSerializable
+final class ClassInfo implements ClassName
 {
     public const UNDEFINED = 'UNDEFINED';
     public const IRI = 'IRI';
     public const UNION = 'UNION';
     public const INTERFACE = 'INTERFACE';
 
-    /** @var PHPClass */
-    private $resource;
+    /** @var ClassName */
+    private $class;
 
-    /** @var self|null */
-    private $parent;
+    /** @var self|null|false */
+    private $parent = false;
 
     /** @var PropertyMetadata[] */
     private $virtualProperties = [];
@@ -51,33 +51,58 @@ final class ClassInfo implements \JsonSerializable
     private $type = self::UNDEFINED;
 
     /** @var bool */
-    private $isAbstract;
+    private $abstract;
 
     /**
      * ClassInfo constructor.
      *
-     * @param PHPClass           $resource
+     * @param ClassName          $class
      * @param PropertyMetadata[] $properties
-     * @param bool               $isAbstract
+     * @param bool               $abstract
      */
-    public function __construct(PHPClass $resource, array $properties = [], bool $isAbstract)
+    public function __construct(ClassName $class, array $properties = [], bool $abstract)
     {
-        $this->resource = $resource;
-        $this->isAbstract = $isAbstract;
+        $this->class = $class;
+        $this->abstract = $abstract;
 
         foreach ($properties as $property) {
             $this->virtualProperties[$property->getName()] = $property;
         }
+        $this->concreteProperties = $abstract ? [] : $this->virtualProperties;
     }
 
     /**
-     * Get resource.
+     * {@inheritdoc}
+     */
+    public function getNamespace(): string
+    {
+        return $this->class->getNamespace();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBaseName(): string
+    {
+        return $this->class->getBaseName();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFullName(): string
+    {
+        return $this->class->getFullName();
+    }
+
+    /**
+     * Get class.
      *
-     * @return PHPClass
+     * @return ClassName
      */
-    public function getResource(): PHPClass
+    public function getClass(): ClassName
     {
-        return $this->resource;
+        return $this->class;
     }
 
     /**
@@ -101,13 +126,13 @@ final class ClassInfo implements \JsonSerializable
     }
 
     /**
-     * Get isAbstract.
+     * Get abstract.
      *
      * @return bool
      */
     public function isAbstract(): bool
     {
-        return $this->isAbstract;
+        return $this->abstract;
     }
 
     /**
@@ -187,6 +212,15 @@ final class ClassInfo implements \JsonSerializable
         return $this->type === $type;
     }
 
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getClass()->getFullName();
+    }
+
     /**
      * Fait remonter les propriétés communes des sous-classes.
      */
diff --git a/src/Models/ClassName.php b/src/Models/ClassName.php
new file mode 100644
index 0000000000000000000000000000000000000000..7309c8be618d26b67dbac5dd6e37a782b159c945
--- /dev/null
+++ b/src/Models/ClassName.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+/*
+ * irstea/ng-model-generator-bundle generates Typescript interfaces for Angular using api-platform metadata.
+ * Copyright (C) 2018 IRSTEA
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License and the GNU
+ * Lesser General Public License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+namespace Irstea\NgModelGeneratorBundle\Models;
+
+/**
+ * Interface ClassName.
+ */
+interface ClassName extends \JsonSerializable
+{
+    /**
+     * Get namespace.
+     *
+     * @return string
+     */
+    public function getNamespace(): string;
+
+    /**
+     * Get baseName.
+     *
+     * @return string
+     */
+    public function getBaseName(): string;
+
+    /**
+     * @return string
+     */
+    public function getFullName(): string;
+
+    /**
+     * @return string
+     */
+    public function __toString();
+}
diff --git a/src/Models/PHPClass.php b/src/Models/PHPClass.php
index 40a3d96b2fad3d995e4f7107816402fc7af889bb..e6ff765c10b85d4a92889c1b97ac97b39e93ac13 100644
--- a/src/Models/PHPClass.php
+++ b/src/Models/PHPClass.php
@@ -24,7 +24,7 @@ use Irstea\NgModelGeneratorBundle\Exceptions\InvalidArgumentException;
 /**
  * Class PHPClass.
  */
-final class PHPClass implements \JsonSerializable
+final class PHPClass implements ClassName
 {
     /** @var string */
     private $namespace;
@@ -72,34 +72,6 @@ final class PHPClass implements \JsonSerializable
         return $this->namespace . $this->baseName;
     }
 
-    /**
-     * @return bool
-     */
-    public function exists(): bool
-    {
-        return class_exists($this->getFullName());
-    }
-
-    /**
-     * @throws \ReflectionException
-     *
-     * @return \ReflectionClass
-     */
-    public function getReflection(): \ReflectionClass
-    {
-        return new \ReflectionClass($this->getFullName());
-    }
-
-    /**
-     * @param string|PHPClass $class
-     *
-     * @return bool
-     */
-    public function is($class): bool
-    {
-        return $this === self::get($class);
-    }
-
     /**
      * @return string
      */
@@ -128,13 +100,13 @@ final class PHPClass implements \JsonSerializable
     }
 
     /**
-     * @param self|string $name
+     * @param ClassName|string $name
      *
-     * @return self
+     * @return ClassName
      */
-    public static function get($name): self
+    public static function get($name): ClassName
     {
-        if ($name instanceof self) {
+        if ($name instanceof ClassName) {
             return $name;
         }
 
diff --git a/src/Models/Types/Objects/Repository.php b/src/Models/Types/Objects/Repository.php
index 733eb78a699078726c58526d9d1d7ab4b0c26a90..42f2b4fb184556549db3da629a573d2d66af7540 100644
--- a/src/Models/Types/Objects/Repository.php
+++ b/src/Models/Types/Objects/Repository.php
@@ -20,7 +20,7 @@
 namespace Irstea\NgModelGeneratorBundle\Models\Types\Objects;
 
 use Doctrine\Common\Inflector\Inflector;
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\Types\Operations\Operation;
 use Irstea\NgModelGeneratorBundle\Models\Types\Operations\Path;
 use Irstea\NgModelGeneratorBundle\Models\Types\Type;
@@ -31,7 +31,7 @@ use Irstea\NgModelGeneratorBundle\TypescriptHelper;
  */
 final class Repository extends ClassType
 {
-    /** @var PHPClass */
+    /** @var ClassName */
     private $resource;
 
     /** @var Operation[] */
@@ -49,13 +49,13 @@ final class Repository extends ClassType
     /**
      * Repository constructor.
      *
-     * @param PHPClass    $resource
+     * @param ClassName   $resource
      * @param Type        $resourceType
      * @param Property    $identifier
      * @param Operation[] $operations
      * @param string      $description
      */
-    public function __construct(PHPClass $resource, Type $resourceType, Property $identifier, array $operations, string $description = '')
+    public function __construct(ClassName $resource, Type $resourceType, Property $identifier, array $operations, string $description = '')
     {
         parent::__construct(
             $resource->getBaseName() . 'Repository',
diff --git a/src/Models/Types/Resources/IRI.php b/src/Models/Types/Resources/IRI.php
index b3ed4f154110296d1d9cf7f13f5652afe260a7c6..ad5cf346ad2c586028d26049b000483252d11719 100644
--- a/src/Models/Types/Resources/IRI.php
+++ b/src/Models/Types/Resources/IRI.php
@@ -19,7 +19,7 @@
 
 namespace Irstea\NgModelGeneratorBundle\Models\Types\Resources;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\Types\AbstractType;
 
 /**
@@ -27,13 +27,13 @@ use Irstea\NgModelGeneratorBundle\Models\Types\AbstractType;
  */
 final class IRI extends AbstractType
 {
-    /** @var PHPClass[] */
+    /** @var ClassName[] */
     private $resources;
 
     /**
      * IRI constructor.
      *
-     * @param PHPClass[] $resources
+     * @param ClassName[] $resources
      */
     public function __construct(array $resources)
     {
@@ -46,7 +46,7 @@ final class IRI extends AbstractType
     private function getNames(): array
     {
         return array_map(
-            function (PHPClass $t): string {
+            function (ClassName $t): string {
                 return $t->getBaseName();
             },
             $this->resources
diff --git a/src/Models/Types/Resources/Representation.php b/src/Models/Types/Resources/Representation.php
index cb976ba51392b3aef1afa5949dc8152f77aaa626..87c89d12999aac889adccee3eec26d65ce10923c 100644
--- a/src/Models/Types/Resources/Representation.php
+++ b/src/Models/Types/Resources/Representation.php
@@ -19,42 +19,58 @@
 
 namespace Irstea\NgModelGeneratorBundle\Models\Types\Resources;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\Types\Objects\InterfaceType;
 use Irstea\NgModelGeneratorBundle\Models\Types\Type;
 
 /**
  * Class Representation.
  */
-final class Representation extends InterfaceType
+final class Representation extends InterfaceType implements ClassName
 {
-    /** @var PHPClass */
+    /** @var ClassName */
     private $resource;
 
     /**
      * {@inheritdoc}
      */
-    public function __construct(PHPClass $resource, string $name, ?Type $parent, $properties = [], string $description = '', array $children = [])
+    public function __construct(ClassName $resource, string $name, ?Type $parent, $properties = [], string $description = '', array $children = [])
     {
         parent::__construct($name, $parent, $properties, $description, $children);
         $this->resource = $resource;
     }
 
     /**
-     * @return string
+     * {@inheritdoc}
+     */
+    public function getNamespace(): string
+    {
+        return $this->resource->getNamespace();
+    }
+
+    /**
+     * {@inheritdoc}
      */
-    public function getResourceName(): string
+    public function getBaseName(): string
     {
         return $this->resource->getBaseName();
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getFullName(): string
+    {
+        return $this->resource->getFullName();
+    }
+
     /**
      * {@inheritdoc}
      */
     public function checkType(string $expr, bool $explicit = false): string
     {
         if (!$explicit) {
-            return sprintf('%sRepository.isValidResource(%s)', $this->getResourceName(), $expr);
+            return sprintf('%sRepository.isValidResource(%s)', $this->getBaseName(), $expr);
         }
 
         return parent::checkType($expr, false);
diff --git a/src/PathParser.php b/src/PathParser.php
index d0b5466ec3ed0c4f510bc7612e48a83c7b4aa3cb..bbf7e2b2e3daec5459a5412a002dfb4889e48462 100644
--- a/src/PathParser.php
+++ b/src/PathParser.php
@@ -19,7 +19,7 @@
 
 namespace Irstea\NgModelGeneratorBundle;
 
-use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
 use Irstea\NgModelGeneratorBundle\Models\Types\Objects\Property;
 use Irstea\NgModelGeneratorBundle\Models\Types\Operations\Parameter;
@@ -37,16 +37,16 @@ final class PathParser implements PathParserInterface
     /** @var Property[] */
     private $properties;
 
-    /** @var PHPClass */
+    /** @var ClassName */
     private $resource;
 
     /**
      * PathParser constructor.
      *
-     * @param PHPClass   $resource
+     * @param ClassName  $resource
      * @param Property[] $properties
      */
-    public function __construct(PHPClass $resource, array $properties)
+    public function __construct(ClassName $resource, array $properties)
     {
         $this->properties = $properties;
         $this->resource = $resource;
diff --git a/src/SerializationMapper.php b/src/SerializationMapper.php
index 9f36310a7c3557c04295fe6b0d9ec33e05900873..d2b0fc0e7005d903ed46b4c88cec679ab0bfa7b1 100644
--- a/src/SerializationMapper.php
+++ b/src/SerializationMapper.php
@@ -24,6 +24,7 @@ use Irstea\NgModelGeneratorBundle\Metadata\PropertyMetadata;
 use Irstea\NgModelGeneratorBundle\Metadata\RepresentationMetadata;
 use Irstea\NgModelGeneratorBundle\Metadata\SerializationMetadata;
 use Irstea\NgModelGeneratorBundle\Models\ClassInfo;
+use Irstea\NgModelGeneratorBundle\Models\ClassName;
 use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Irstea\NgModelGeneratorBundle\Models\Types\Alias;
 use Irstea\NgModelGeneratorBundle\Models\Types\ArrayType;
@@ -157,19 +158,17 @@ final class SerializationMapper implements TypeFactoryInterface
      */
     private function mapRepresentation(RepresentationMetadata $repr): Type
     {
-        $resourceClass = $repr->getClass();
-
-        $classInfo = $this->getClassInfo($resourceClass);
+        $classInfo = $this->getClassInfo($repr);
 
         if ($classInfo->isUnion()) {
             $types = [];
             foreach ($classInfo->iterateInterfaceDescendants() as $child) {
-                $types[] = $this->get($child->getResource()->getFullName());
+                $types[] = $this->get($child->getClass()->getFullName());
             }
 
             switch (\count($types)) {
                 case 0:
-                    throw new DomainException(sprintf('Union with no children: %s', $resourceClass));
+                    throw new DomainException(sprintf('Union with no children: %s', $repr));
                 case 1:
                     return new Reference($types[0]);
                 default:
@@ -178,36 +177,36 @@ final class SerializationMapper implements TypeFactoryInterface
         }
 
         if ($classInfo->isIRI()) {
-            return new IRI([$resourceClass]);
+            return new IRI([$repr]);
         }
 
         if (!$classInfo->isInterface()) {
-            throw new DomainException(sprintf('Cannot map %s', $resourceClass->getFullName()));
+            throw new DomainException(sprintf('Cannot map %s', $repr));
         }
 
         $parent = null;
         $parentInfo = $classInfo->getParent();
         if ($parentInfo !== null && $parentInfo->isInterface()) {
-            $parent = $this->get($parentInfo->getResource()->getFullName());
+            $parent = $this->get($parentInfo->getFullName());
         }
 
         $properties = $this->mapProperties($classInfo);
 
         $desc = [];
-        $desc[] = 'Resource: ' . $resourceClass->getFullName();
+        $desc[] = 'Resource: ' . $repr;
         $desc[] = 'Direction: ' . ($this->serialization->isNormalization() ? 'response' : 'request');
         $desc[] = sprintf('Serialization groups: %s', implode(', ', $this->serialization->getGroups()) ?: '-');
         $desc = trim(implode("\n", $desc));
 
         $children = [];
-        /* @var PHPClass $class */
+        /* @var ClassName $class */
         foreach ($classInfo->getChildren() as $child) {
             if ($child->isInterface()) {
-                $children[] = $this->get($child->getResource()->getFullName());
+                $children[] = $this->get($child->getFullName());
             }
         }
 
-        return new Representation($resourceClass, $repr->getName(), $parent, $properties, $desc, $children);
+        return new Representation($repr, $repr->getName(), $parent, $properties, $desc, $children);
     }
 
     /**
@@ -219,7 +218,7 @@ final class SerializationMapper implements TypeFactoryInterface
     {
         $resources = [];
         foreach ($classInfo->iterateConcreteDescendants() as $child) {
-            $resources[] = $child->getResource();
+            $resources[] = $child;
         }
 
         return new IRI($resources);
@@ -248,7 +247,7 @@ final class SerializationMapper implements TypeFactoryInterface
             throw new DomainException(
                 sprintf(
                     'Resource %s must have at most one identifier, found %d',
-                    $classInfo->getResource()->getBaseName(),
+                    $classInfo->getBaseName(),
                     $identifierCount
                 )
             );
@@ -286,7 +285,7 @@ final class SerializationMapper implements TypeFactoryInterface
     {
         $types = [];
         foreach ($classInfo->iterateConcreteDescendants() as $child) {
-            $types[] = StringConst::get($child->getResource()->getBaseName());
+            $types[] = StringConst::get($child->getBaseName());
         }
 
         return Union::create($types);
@@ -342,13 +341,13 @@ final class SerializationMapper implements TypeFactoryInterface
     }
 
     /**
-     * @param PHPClass $class
+     * @param ClassName $class
      *
      * @return ClassInfo
      */
-    private function getClassInfo(PHPClass $class): ClassInfo
+    private function getClassInfo(ClassName $class): ClassInfo
     {
-        if (!isset($this->classInfo)) {
+        if ($this->classInfo === null) {
             $this->init();
         }
 
@@ -361,8 +360,11 @@ final class SerializationMapper implements TypeFactoryInterface
 
         // Crée les instances de métadonnées sur les ressources
         foreach ($reprs as $className => $repr) {
-            $class = $repr->getClass();
-            $this->classInfo[$className] = new ClassInfo($class, $repr->getProperties(), $class->getReflection()->isAbstract());
+            $this->classInfo[$className] = new ClassInfo(
+                $repr,
+                $repr->getProperties(),
+                $repr->isAbstract()
+            );
         }
 
         // Crée les liens de parenté
diff --git a/tests/PHPClassTest.php b/tests/Models/PHPClassTest.php
similarity index 82%
rename from tests/PHPClassTest.php
rename to tests/Models/PHPClassTest.php
index fc49a6052e7b0935d9ff647ebd6b9213259c1603..c6b2c5dab1a115f24a976d037139a1e60007efc3 100644
--- a/tests/PHPClassTest.php
+++ b/tests/Models/PHPClassTest.php
@@ -17,7 +17,7 @@
  * <https://www.gnu.org/licenses/>.
  */
 
-namespace Irstea\NgModelGeneratorBundle\Tests;
+namespace Irstea\NgModelGeneratorBundle\Tests\Models;
 
 use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use PHPUnit\Framework\TestCase;
@@ -98,28 +98,4 @@ class PHPClassTest extends TestCase
             [PHPClass::class],
         ];
     }
-
-    /**
-     * @param $expected
-     * @param $fqcn
-     *
-     * @dataProvider existsTestCases
-     */
-    public function testExists(bool $expected, string $fqcn)
-    {
-        $class = PHPClass::get($fqcn);
-        self::assertEquals($expected, $class->exists());
-    }
-
-    /**
-     * @return array
-     */
-    public function existsTestCases(): array
-    {
-        return [
-            [false, 'Foo'],
-            [true, \stdClass::class],
-            [true, PHPClass::class],
-        ];
-    }
 }