diff --git a/src/Context.php b/src/Context.php
index eeb6c3015c613b66dfbc962c3d2bc727f5dd1435..ac9cb04c3d4d5571b639f1c65d977d6dc017bf25 100644
--- a/src/Context.php
+++ b/src/Context.php
@@ -19,12 +19,14 @@
 
 namespace Irstea\NgModelGeneratorBundle;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Class Context.
  */
 class Context implements ContextInterface
 {
-    /** @var string */
+    /** @var PHPClass */
     private $rootClass;
 
     /** @var bool */
@@ -44,7 +46,7 @@ class Context implements ContextInterface
      * @param string[]    $groups
      * @param \string[][] $defaultGroups
      */
-    public function __construct(string $rootClass, array $defaultGroups, bool $normalization = false, array $groups = [])
+    public function __construct(PHPClass $rootClass, array $defaultGroups, bool $normalization = false, array $groups = [])
     {
         $this->rootClass = $rootClass;
         $this->defaultGroups = $defaultGroups;
@@ -71,7 +73,7 @@ class Context implements ContextInterface
     }
 
     /**
-     * @param bool $normalization
+     * @param string[] $groups
      *
      * @return Context
      */
@@ -93,9 +95,9 @@ class Context implements ContextInterface
     /**
      * Get rootClass.
      *
-     * @return string
+     * @return PHPClass
      */
-    public function getRootClass(): string
+    public function getRootClass(): PHPClass
     {
         return $this->rootClass;
     }
@@ -117,12 +119,12 @@ class Context implements ContextInterface
     }
 
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return string[]
      */
-    public function getDefaultGroups(string $className): array
+    public function getDefaultGroups(PHPClass $class): array
     {
-        return $this->defaultGroups[$this->normalization ? 'normalization' : 'denormalization'][$className] ?? [];
+        return $this->defaultGroups[$this->normalization ? 'normalization' : 'denormalization'][$class->getFullName()] ?? [];
     }
 }
diff --git a/src/ContextInterface.php b/src/ContextInterface.php
index d03fdf91d82298f67f1c5ac8f7b6c86bd0becf37..0b02806664be49c2a382d3da70c971a96b29ee0f 100644
--- a/src/ContextInterface.php
+++ b/src/ContextInterface.php
@@ -19,6 +19,8 @@
 
 namespace Irstea\NgModelGeneratorBundle;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Interface ContextInterface.
  */
@@ -32,7 +34,7 @@ interface ContextInterface
     public function withNormalization(bool $normalization): self;
 
     /**
-     * @param bool $normalization
+     * @param string[] $groups
      *
      * @return Context
      */
@@ -41,9 +43,9 @@ interface ContextInterface
     /**
      * Get rootClass.
      *
-     * @return string
+     * @return PHPClass
      */
-    public function getRootClass(): string;
+    public function getRootClass(): PHPClass;
 
     /**
      * @return bool
@@ -56,9 +58,9 @@ interface ContextInterface
     public function getGroups(): array;
 
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return string[]
      */
-    public function getDefaultGroups(string $className): array;
+    public function getDefaultGroups(PHPClass $class): array;
 }
diff --git a/src/DefaultNamingStrategy.php b/src/DefaultNamingStrategy.php
index 5f7ec0e802d7e27e49ed34e274ec9eea241bacec..656f8b0f48b94f6e0f530f688d98a0a8268ce473 100644
--- a/src/DefaultNamingStrategy.php
+++ b/src/DefaultNamingStrategy.php
@@ -19,6 +19,8 @@
 
 namespace Irstea\NgModelGeneratorBundle;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Class DefaultNamingStrategy.
  */
@@ -27,7 +29,7 @@ final class DefaultNamingStrategy implements NamingStrategy
     /**
      * {@inheritdoc}
      */
-    public function getName(ContextInterface $ctx, string $resourceClass): string
+    public function getName(ContextInterface $ctx, PHPClass $resourceClass): string
     {
         $parts = array_diff(
             $ctx->getGroups(),
@@ -35,7 +37,7 @@ final class DefaultNamingStrategy implements NamingStrategy
             $ctx->getDefaultGroups($ctx->getRootClass())
         );
 
-        $baseName = FQCN::baseName($resourceClass);
+        $baseName = $resourceClass->getBaseName();
         $shortPrefix = $ctx->isNormalization() ? '' : 'Put';
         $fullPrefix = $ctx->isNormalization() ? 'Get' : 'Put';
 
@@ -46,7 +48,7 @@ final class DefaultNamingStrategy implements NamingStrategy
                 array_unshift($parts, $shortPrefix . $baseName);
             }
         } else {
-            $rootBaseName = FQCN::baseName($ctx->getRootClass());
+            $rootBaseName = $ctx->getRootClass()->getBaseName();
             $rootGroup = $fullPrefix . $rootBaseName;
             if (\in_array($rootGroup, $parts, true)) {
                 array_unshift($parts, $rootBaseName);
diff --git a/src/Metadata/CachingMetadataFactory.php b/src/Metadata/CachingMetadataFactory.php
index 4f527313244d5e0b17c094f81d6cb8cbfcc7f491..018e6568ded4183d388649c09a2487284285f1eb 100644
--- a/src/Metadata/CachingMetadataFactory.php
+++ b/src/Metadata/CachingMetadataFactory.php
@@ -21,6 +21,7 @@ namespace Irstea\NgModelGeneratorBundle\Metadata;
 
 use Doctrine\Common\Cache\ArrayCache;
 use Doctrine\Common\Cache\Cache;
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 
 /**
  * Class CachingMetadataFactory.
@@ -48,43 +49,46 @@ final class CachingMetadataFactory implements MetadataFactoryInterface
     /**
      * {@inheritdoc}
      */
-    public function isResource(string $className): bool
+    public function isResource(PHPClass $class): bool
     {
-        return $this->inner->isResource($className);
+        return $this->inner->isResource($class);
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getResourceMetadata(string $className): ResourceMetadata
+    public function getResourceMetadata(PHPClass $class): ResourceMetadata
     {
-        return $this->memoize(__METHOD__, $className, function ($className) {
-            return $this->inner->getResourceMetadata($className)->setFactory($this);
+        return $this->memoize(__METHOD__, $class->getFullName(), function () use ($class) {
+            return $this->inner->getResourceMetadata($class)->setFactory($this);
         });
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getOperations(string $className): array
+    public function getOperations(PHPClass $class): array
     {
-        return $this->memoize(__METHOD__, $className, [$this->inner, 'getOperations']);
+        return $this->memoize(__METHOD__, $class->getFullName(), function () use ($class) {
+            return $this->inner->getOperations($class);
+        });
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getProperties(string $className, array $groups = []): array
+    public function getProperties(PHPClass $class, array $groups = []): array
     {
         sort($groups);
-        $key = $className . '::' . implode('-', $groups);
+        $key = $class->getFullName() . '::' . implode('-', $groups);
 
-        return $this->memoize(__METHOD__, $key, function () use ($className, $groups) {
-            return $this->inner->getProperties($className, $groups);
+        return $this->memoize(__METHOD__, $key, function () use ($class, $groups) {
+            return $this->inner->getProperties($class, $groups);
         });
     }
 
     /**
+     * @param string   $namespace
      * @param string   $key
      * @param callable $compute
      *
diff --git a/src/Metadata/MetadataFactory.php b/src/Metadata/MetadataFactory.php
index 523a8b329167bbfba48cb01dfa5d74e179fc5ba8..95ebdd784c694a9cf9440eda50d20929d3cdbe6c 100644
--- a/src/Metadata/MetadataFactory.php
+++ b/src/Metadata/MetadataFactory.php
@@ -28,6 +28,7 @@ use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInte
 use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
 use ApiPlatform\Core\Metadata\Resource\ResourceMetadata as APIResourceMetadata;
 use ApiPlatform\Core\PathResolver\OperationPathResolverInterface;
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Psr\Container\ContainerInterface;
 use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
 
@@ -100,30 +101,27 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param string $className
-     *
-     * @return bool
+     * {@inheritdoc}
      */
-    public function isResource(string $className): bool
+    public function isResource(PHPClass $class): bool
     {
-        return $this->resourceClassResolver->isResourceClass($className);
+        return $this->resourceClassResolver->isResourceClass($class->getFullName());
     }
 
     /**
-     * @param string $className
-     *
-     * @return ResourceMetadata
+     * {@inheritdoc}
      */
-    public function getResourceMetadata(string $className): ResourceMetadata
+    public function getResourceMetadata(PHPClass $class): ResourceMetadata
     {
+        $className = $class->getFullName();
         $metadata = $this->resourceMetadataFactory->create($className);
 
         $classMeta = new \ReflectionClass($className);
         $parentClass = $classMeta->getParentClass();
 
         return new ResourceMetadata(
-            $className,
-            $parentClass ? $parentClass->getName() : null,
+            $class,
+            $parentClass ? PHPClass::get($parentClass->getName()) : null,
             $metadata->getShortName(),
             $metadata->getDescription(),
             $classMeta->isAbstract(),
@@ -164,13 +162,13 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return OperationMetadata[]
      */
-    public function getOperations(string $className): array
+    public function getOperations(PHPClass $class): array
     {
-        $resourceMetadata = $this->resourceMetadataFactory->create($className);
+        $resourceMetadata = $this->resourceMetadataFactory->create($class->getFullName());
 
         $operations = [];
 
@@ -179,7 +177,7 @@ final class MetadataFactory implements MetadataFactoryInterface
             OperationType::COLLECTION => $resourceMetadata->getCollectionOperations(),
         ] as $type => $ops) {
             foreach ($ops as $name => $operation) {
-                $operations[] = $this->getOperation($className, $resourceMetadata, $name, $type, $operation);
+                $operations[] = $this->getOperation($class, $resourceMetadata, $name, $type, $operation);
             }
         }
 
@@ -187,7 +185,7 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
-     * @param string              $className
+     * @param PHPClass            $class
      * @param APIResourceMetadata $resourceMetadata
      * @param string              $name
      * @param string              $type
@@ -196,16 +194,16 @@ final class MetadataFactory implements MetadataFactoryInterface
      * @return OperationMetadata
      */
     private function getOperation(
-        string $className,
+        PHPClass $class,
         APIResourceMetadata $resourceMetadata,
         string $name,
         string $type,
         array $operation
     ): OperationMetadata {
         if ($type === OperationType::ITEM) {
-            $method = $this->operationMethodResolver->getItemOperationMethod($className, $name);
+            $method = $this->operationMethodResolver->getItemOperationMethod($class->getFullName(), $name);
         } else {
-            $method = $this->operationMethodResolver->getCollectionOperationMethod($className, $name);
+            $method = $this->operationMethodResolver->getCollectionOperationMethod($class->getFullName(), $name);
         }
 
         /** @noinspection PhpMethodParametersCountMismatchInspection */
@@ -227,7 +225,7 @@ final class MetadataFactory implements MetadataFactoryInterface
             $getAttribute('normalization_context', [])['groups'] ?? [],
             $getAttribute('denormalization_context', [])['groups'] ?? [],
             $getAttribute('requirements', []),
-            $this->getFilters($className, $getAttribute('filters', [])),
+            $this->getFilters($class, $getAttribute('filters', [])),
             $this->buildPagination(
                 $getAttribute('pagination_enabled', true),
                 $getAttribute('pagination_client_items_per_page', true)
@@ -236,9 +234,12 @@ final class MetadataFactory implements MetadataFactoryInterface
     }
 
     /**
+     * @param PHPClass $class
+     * @param array    $filterIds
+     *
      * @return FilterInterface[]
      */
-    private function getFilters(string $className, array $filterIds): array
+    private function getFilters(PHPClass $class, array $filterIds): array
     {
         $filters = [];
 
@@ -249,7 +250,7 @@ final class MetadataFactory implements MetadataFactoryInterface
 
             /** @var FilterInterface $filter */
             $filter = $this->filterLocator->get($filterId);
-            foreach ($filter->getDescription($className) as $name => $filterParameter) {
+            foreach ($filter->getDescription($class->getFullName()) as $name => $filterParameter) {
                 $filters[$name] = $filterParameter;
             }
         }
@@ -266,8 +267,9 @@ final class MetadataFactory implements MetadataFactoryInterface
      *
      * @return PropertyMetadata[]
      */
-    public function getProperties(string $className, array $groups = []): array
+    public function getProperties(PHPClass $class, array $groups = []): array
     {
+        $className = $class->getFullName();
         $properties = [];
 
         $options = $groups ? ['serializer_groups' => $groups] : [];
@@ -298,7 +300,7 @@ final class MetadataFactory implements MetadataFactoryInterface
                 $leafType = $leafType->getCollectionValueType();
             }
             $propClass = $leafType ? $leafType->getClassName() : null;
-            if ($propClass && $this->isResource($propClass)) {
+            if ($propClass && $this->isResource(PHPClass::get($propClass))) {
                 $link = true;
                 $embedded = \count($this->propertyNameCollectionFactory->create($propClass, $options)) > 0;
             }
diff --git a/src/Metadata/MetadataFactoryInterface.php b/src/Metadata/MetadataFactoryInterface.php
index 67929ad25d6cf4d064c9f43049cabd126557861f..2d6d1964c55ba07bf22fcb8e7bbcbfb9944bb257 100644
--- a/src/Metadata/MetadataFactoryInterface.php
+++ b/src/Metadata/MetadataFactoryInterface.php
@@ -19,39 +19,41 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Interface MetadataFactoryInterface.
  */
 interface MetadataFactoryInterface
 {
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return bool
      */
-    public function isResource(string $className): bool;
+    public function isResource(PHPClass $class): bool;
 
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return ResourceMetadata
      */
-    public function getResourceMetadata(string $className): ResourceMetadata;
+    public function getResourceMetadata(PHPClass $class): ResourceMetadata;
 
     /**
-     * @param string $className
+     * @param PHPClass $class
      *
      * @return OperationMetadata[]
      */
-    public function getOperations(string $className): array;
+    public function getOperations(PHPClass $class): array;
 
     /**
-     * @param string $className
-     * @param array  $groups
+     * @param PHPClass $class
+     * @param array    $groups
      *
      * @return PropertyMetadata[]
      */
-    public function getProperties(string $className, array $groups = []): array;
+    public function getProperties(PHPClass $class, array $groups = []): array;
 
     /**
      * @return PaginationMetadata
diff --git a/src/Metadata/Normalizer.php b/src/Metadata/Normalizer.php
index d8f4fd2f172ab9fc7554102ca935182290387235..bdc59e4999cc637b2edd81c6fc5c8582934fb043 100644
--- a/src/Metadata/Normalizer.php
+++ b/src/Metadata/Normalizer.php
@@ -106,7 +106,7 @@ final class Normalizer implements NormalizerInterface
         /** @var string $className */
         foreach ($doc->getResourceNameCollection() as $className) {
             $meta = $this->metadataFactory->getResourceMetadata($className);
-            $context['resourceClass'] = $className;
+            $context['resourceClassName'] = $className;
 
             $resources[$meta->getShortName()] = $this->normalizeResource($meta, $context);
         }
diff --git a/src/Metadata/ResourceMetadata.php b/src/Metadata/ResourceMetadata.php
index ad114e9997ddfb466546f6997d0c6165807dac9b..cda350562ba0aeca44a32f69ae48abc0ce73c95c 100644
--- a/src/Metadata/ResourceMetadata.php
+++ b/src/Metadata/ResourceMetadata.php
@@ -19,6 +19,8 @@
 
 namespace Irstea\NgModelGeneratorBundle\Metadata;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Class ResourceMetadata.
  */
@@ -27,11 +29,11 @@ class ResourceMetadata implements \JsonSerializable
     use PaginedTrait;
     use SerializationGroupsTrait;
 
-    /** @var string */
-    private $className;
+    /** @var PHPClass */
+    private $class;
 
-    /** @var string|null */
-    private $parentClassName;
+    /** @var PHPClass|null */
+    private $parentClass;
 
     /** @var string */
     private $shortName;
@@ -48,8 +50,8 @@ class ResourceMetadata implements \JsonSerializable
     /**
      * ResourceMetadata constructor.
      *
-     * @param string                   $className
-     * @param string|null              $parentClassName
+     * @param PHPClass                 $class
+     * @param PHPClass|null            $parentClass
      * @param string                   $shortName
      * @param string                   $description
      * @param bool                     $abstract
@@ -59,8 +61,8 @@ class ResourceMetadata implements \JsonSerializable
      * @param MetadataFactoryInterface $factory
      */
     public function __construct(
-        string $className,
-        ?string $parentClassName,
+        PHPClass $class,
+        ?PHPClass $parentClass,
         string $shortName,
         string $description,
         bool $abstract,
@@ -69,8 +71,8 @@ class ResourceMetadata implements \JsonSerializable
         array $denormalizationGroups,
         MetadataFactoryInterface $factory
     ) {
-        $this->className = $className;
-        $this->parentClassName = $parentClassName;
+        $this->class = $class;
+        $this->parentClass = $parentClass;
         $this->shortName = $shortName;
         $this->description = $description;
         $this->factory = $factory;
@@ -101,27 +103,37 @@ class ResourceMetadata implements \JsonSerializable
      */
     public function getClassName(): string
     {
-        return $this->className;
+        return $this->class->getFullName();
     }
 
     /**
-     * Get parentClassName.
+     * Get shortName.
      *
-     * @return string|null
+     * @return string
      */
-    public function getParentClassName(): ?string
+    public function getShortName(): string
     {
-        return $this->parentClassName;
+        return $this->class->getBaseName();
     }
 
     /**
-     * Get shortName.
+     * Get parentClass.
      *
-     * @return string
+     * @return PHPClass|null
      */
-    public function getShortName(): string
+    public function getParentClass(): ?PHPClass
+    {
+        return $this->parentClass;
+    }
+
+    /**
+     * Get parentClassName.
+     *
+     * @return string|null
+     */
+    public function getParentClassName(): ?string
     {
-        return $this->shortName;
+        return $this->parentClass ? $this->parentClass->getFullName() : null;
     }
 
     /**
@@ -155,7 +167,7 @@ class ResourceMetadata implements \JsonSerializable
             function (OperationMetadata $op): OperationMetadata {
                 return $op->withResource($this);
             },
-            $this->factory->getOperations($this->className)
+            $this->factory->getOperations($this->class)
         );
     }
 
@@ -172,7 +184,7 @@ class ResourceMetadata implements \JsonSerializable
             function (PropertyMetadata $p): PropertyMetadata {
                 return $p->withResource($this);
             },
-            $this->factory->getProperties($this->className, $groups)
+            $this->factory->getProperties($this->class, $groups)
         );
     }
 
@@ -182,8 +194,8 @@ class ResourceMetadata implements \JsonSerializable
     public function jsonSerialize()
     {
         return [
-            'class_name'             => $this->className,
-            'parent_class_name'      => $this->parentClassName,
+            'class_name'             => $this->class->getFullName(),
+            'parent_class_name'      => $this->getParentClassName(),
             'short_name'             => $this->shortName,
             'description'            => $this->description,
             'abstract'               => $this->abstract,
diff --git a/src/ModelGenerator.php b/src/ModelGenerator.php
index dda572a57ab033ddfeca6e2ecad5984e224a5fb6..eec2185cce10fc63d4f113761539574c1e942cd1 100644
--- a/src/ModelGenerator.php
+++ b/src/ModelGenerator.php
@@ -27,6 +27,7 @@ use Irstea\NgModelGeneratorBundle\Iterators\UniqueFilter;
 use Irstea\NgModelGeneratorBundle\Metadata\MetadataFactoryInterface;
 use Irstea\NgModelGeneratorBundle\Metadata\ResourceMetadata;
 use Irstea\NgModelGeneratorBundle\Models\Declaration;
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Irstea\NgModelGeneratorBundle\Models\Types\Alias;
 use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
 use Irstea\NgModelGeneratorBundle\Models\Types\Generics\GenericDef;
@@ -244,8 +245,12 @@ final class ModelGenerator
             'denormalization' => [],
         ];
 
-        /** @var ResourceMetadata $resourceMeta */
-        foreach ($this->getResourceMetadata() as $className => $resourceMeta) {
+        /**
+         * @var PHPClass
+         * @var ResourceMetadata $resourceMeta
+         */
+        foreach ($this->getResourceMetadata() as $class => $resourceMeta) {
+            $className = $class->getFullName();
             foreach (['normalization', 'denormalization'] as $normalization) {
                 $groups = $resourceMeta->getSerializationGroups($normalization === 'normalization');
                 sort($groups);
@@ -264,15 +269,11 @@ final class ModelGenerator
     private function getResourceMetadata(): \Iterator
     {
         $classNames = iterator_to_array($this->documentation->getResourceNameCollection()->getIterator());
-        usort(
-            $classNames,
-            function (string $a, string $b): bool {
-                return FQCN::baseName($a) > FQCN::baseName($b);
-            }
-        );
+        $classes = array_map([PHPClass::class, 'get'], $classNames);
+        usort($classes, [PHPClass::class, 'baseNameOrdering']);
 
-        foreach ($classNames as $className) {
-            yield $className => $this->metadataFactory->getResourceMetadata($className);
+        foreach ($classes as $class) {
+            yield $class => $this->metadataFactory->getResourceMetadata($class);
         }
     }
 
@@ -285,13 +286,14 @@ final class ModelGenerator
     {
         $representations = [];
 
-        /** @var string $className */
-        foreach ($this->getResourceMetadata() as $className => $resourceMeta) {
+        /** @var PHPClass $class */
+        foreach ($this->getResourceMetadata() as $class => $resourceMeta) {
+            $className = $class->getFullName();
             $representations[$className] = [];
 
             foreach (['normalization', 'denormalization'] as $normalization) {
                 $ctx = new Context(
-                    $className,
+                    $class,
                     $this->defaultGroups,
                     $normalization === 'normalization',
                     $this->defaultGroups[$normalization][$className]
@@ -316,22 +318,26 @@ final class ModelGenerator
         $repositories = [];
         $iriPatterns = [];
 
-        foreach ($this->getResourceMetadata() as $className => $resourceMeta) {
+        /**
+         * @var PHPClass
+         * @var ResourceMetadata $resourceMeta
+         */
+        foreach ($this->getResourceMetadata() as $class => $resourceMeta) {
             $repoName = $resourceMeta->getShortName() . 'Repository';
 
-            $ctx = new Context($className, $this->defaultGroups);
+            $ctx = new Context($class, $this->defaultGroups);
 
             $repositories[$repoName] = $this->typeFactory->getOrCreate(
                 $repoName,
 
-                function () use ($resourceMeta, $className, &$iriPatterns, $ctx): Type {
+                function () use ($resourceMeta, $class, &$iriPatterns, $ctx): Type {
                     $operations = [];
 
                     foreach ($resourceMeta->getOperations() as $operation) {
                         $mapper = new OperationMapper(
                             $this->typeFactory->withContext($ctx),
                             $operation,
-                            $this->resources[$className]['normalization'],
+                            $this->resources[$class->getFullName()]['normalization'],
                             $ctx
                         );
                         $operations[] = $operation = $mapper();
diff --git a/src/Models/PHPClass.php b/src/Models/PHPClass.php
new file mode 100644
index 0000000000000000000000000000000000000000..60954b99d608c178c570cb8c667808891cff887a
--- /dev/null
+++ b/src/Models/PHPClass.php
@@ -0,0 +1,123 @@
+<?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;
+
+use Irstea\NgModelGeneratorBundle\Exceptions\InvalidArgumentException;
+
+/**
+ * Class PHPClass.
+ */
+final class PHPClass implements \JsonSerializable
+{
+    use MultitonTrait;
+
+    /** @var string */
+    private $namespace;
+
+    /** @var string */
+    private $baseName;
+
+    /**
+     * ClassName constructor.
+     *
+     * @param string $name
+     */
+    private function __construct(string $name)
+    {
+        $groups = [];
+        if (!preg_match('/^\\\\?((?:\w+\\\\)*)(\w+)$/i', $name, $groups)) {
+            throw new InvalidArgumentException("Invalid PHP class name: $name");
+        }
+        [, $this->namespace, $this->baseName] = $groups;
+    }
+
+    /**
+     * Get namespace.
+     *
+     * @return string
+     */
+    public function getNamespace(): string
+    {
+        return $this->namespace;
+    }
+
+    /**
+     * Get baseName.
+     *
+     * @return string
+     */
+    public function getBaseName(): string
+    {
+        return $this->baseName;
+    }
+
+    /**
+     * @return string
+     */
+    public function getFullName(): string
+    {
+        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());
+    }
+
+    /**
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->getFullName();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function jsonSerialize()
+    {
+        return $this->getFullName();
+    }
+
+    /**
+     * @param PHPClass $a
+     * @param PHPClass $b
+     *
+     * @return bool
+     */
+    public static function baseNameOrdering(PHPClass $a, PHPClass $b): bool
+    {
+        return $a->getBaseName() > $b->getBaseName();
+    }
+}
diff --git a/src/NamingStrategy.php b/src/NamingStrategy.php
index e5184a7d84ca02763f491446ce0db682af3db9a2..0f8efaec9525a3ff0b7c9a651e402e7e1835a92d 100644
--- a/src/NamingStrategy.php
+++ b/src/NamingStrategy.php
@@ -19,6 +19,8 @@
 
 namespace Irstea\NgModelGeneratorBundle;
 
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+
 /**
  * Interface NamingStrategy.
  */
@@ -26,9 +28,9 @@ interface NamingStrategy
 {
     /**
      * @param ContextInterface $context
-     * @param string           $resourceClass
+     * @param PHPClass         $resourceClass
      *
      * @return mixed
      */
-    public function getName(ContextInterface $context, string $resourceClass);
+    public function getName(ContextInterface $context, PHPClass $resourceClass);
 }
diff --git a/src/ResourceTypeFactory.php b/src/ResourceTypeFactory.php
index 3decfe9657ae3edc78ce6d5aebd0d01f165becd0..986f28dce6061afb3631a53029e9a3e4d879baf7 100644
--- a/src/ResourceTypeFactory.php
+++ b/src/ResourceTypeFactory.php
@@ -22,6 +22,7 @@ namespace Irstea\NgModelGeneratorBundle;
 use Irstea\NgModelGeneratorBundle\Exceptions\DomainException;
 use Irstea\NgModelGeneratorBundle\Metadata\MetadataFactoryInterface;
 use Irstea\NgModelGeneratorBundle\Metadata\PropertyMetadata;
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use Irstea\NgModelGeneratorBundle\Models\Types\Collection;
 use Irstea\NgModelGeneratorBundle\Models\Types\Generics\GenericRef;
 use Irstea\NgModelGeneratorBundle\Models\Types\Objects\HierarchicalObject;
@@ -111,13 +112,15 @@ final class ResourceTypeFactory implements TypeFactoryInterface
             return $this->typeFactory->get($name);
         }
 
-        if ($this->metadataFactory->isResource($name)) {
-            $reprName = $this->namingStrategy->getName($this->context, $name);
+        $class = PHPClass::get($name);
+
+        if ($this->metadataFactory->isResource($class)) {
+            $reprName = $this->namingStrategy->getName($this->context, $class);
 
             return $this->typeFactory->getOrCreate(
                 $reprName,
-                function () use ($name, $reprName): Type {
-                    return $this->mapRepresentation($name, $reprName);
+                function () use ($class, $reprName): Type {
+                    return $this->mapRepresentation($class, $reprName);
                 }
             );
         }
@@ -150,25 +153,24 @@ final class ResourceTypeFactory implements TypeFactoryInterface
     }
 
     /**
-     * @param string $name
-     * @param string $resourceClass
+     * @param string   $name
+     * @param PHPClass $resourceClass
      *
      * @return Type
      */
-    private function mapRepresentation(string $resourceClass, string $name): Type
+    private function mapRepresentation(PHPClass $resourceClass, string $name): Type
     {
         $resourceMeta = $this->metadataFactory->getResourceMetadata($resourceClass);
 
         $normalization = $this->context->isNormalization();
         $groups = $this->context->getGroups();
 
-        $propertiesMeta = $resourceMeta->getProperties($groups);
-        $properties = $this->mapProperties($propertiesMeta);
+        $properties = $this->mapProperties($resourceMeta->getProperties());
 
         $parent = null;
-        $parentClass = $resourceMeta->getParentClassName();
-        if ($parentClass) {
-            $parent = $this->get($parentClass)->dereference();
+        $parentClassName = $resourceMeta->getParentClassName();
+        if ($parentClassName) {
+            $parent = $this->get($parentClassName);
             if ($parent instanceof HierarchicalObject) {
                 $parentReflClass = new \ReflectionClass($parentClass);
                 if ($parentReflClass->isAbstract()) {
@@ -184,7 +186,6 @@ final class ResourceTypeFactory implements TypeFactoryInterface
 
         $desc = explode("\n", $resourceMeta->getDescription());
         $desc[] = 'Resource: ' . $resourceClass;
-        $desc[] = 'Parent: ' . ($parentClass ?: '-');
         $desc[] = 'Direction: ' . ($normalization ? 'response' : 'request');
         $desc[] = sprintf('Serialization groups: %s', $groups ? implode(', ', $groups) : '-');
         $desc = trim(implode("\n", $desc));
diff --git a/tests/DefaultNamingStrategyTest.php b/tests/DefaultNamingStrategyTest.php
index d71c35ecc9e25df07451b36ff29f0470088094c7..51adc335e9a2c262765d29952eb46d9628d382f3 100644
--- a/tests/DefaultNamingStrategyTest.php
+++ b/tests/DefaultNamingStrategyTest.php
@@ -21,6 +21,7 @@ namespace Irstea\NgModelGeneratorBundle\Tests;
 
 use Irstea\NgModelGeneratorBundle\ContextInterface;
 use Irstea\NgModelGeneratorBundle\DefaultNamingStrategy;
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
 use PHPUnit\Framework\TestCase;
 use Prophecy\Argument;
 use Prophecy\Prophecy\ObjectProphecy;
@@ -33,15 +34,18 @@ class DefaultNamingStrategyTest extends TestCase
     /**
      * @dataProvider getNameTestCaseProvider
      */
-    public function testGetName(string $expected, string $resourceClass, string $rootClass, bool $normalization, array $groups, array $defaultGroups)
+    public function testGetName(string $expected, string $resourceClassName, string $rootClassName, bool $normalization, array $groups, array $defaultGroups)
     {
+        $resourceClass = PHPClass::get($resourceClassName);
+        $rootClass = PHPClass::get($rootClassName);
+
         /** @var ObjectProphecy|ContextInterface $ctx */
         $ctx = $this->prophesize(ContextInterface::class);
         $ctx->getRootClass()->willReturn($rootClass);
         $ctx->isNormalization()->willReturn($normalization);
         $ctx->getGroups()->willReturn($groups);
-        $ctx->getDefaultGroups(Argument::type('string'))->will(function ($args) use ($defaultGroups) {
-            return $defaultGroups[$args[0]] ?? [];
+        $ctx->getDefaultGroups(Argument::type(PHPClass::class))->will(function ($args) use ($defaultGroups) {
+            return $defaultGroups[$args[0]->getFullName()] ?? [];
         });
 
         $strategy = new DefaultNamingStrategy();
diff --git a/tests/PHPClassTest.php b/tests/PHPClassTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc49a6052e7b0935d9ff647ebd6b9213259c1603
--- /dev/null
+++ b/tests/PHPClassTest.php
@@ -0,0 +1,125 @@
+<?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\Tests;
+
+use Irstea\NgModelGeneratorBundle\Models\PHPClass;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Class PHPClassTest.
+ */
+class PHPClassTest extends TestCase
+{
+    /**
+     * @param $expected
+     * @param $fqcn
+     *
+     * @dataProvider getBaseNameTestCases
+     */
+    public function testGetBaseName(string $expected, string $fqcn)
+    {
+        $class = PHPClass::get($fqcn);
+        self::assertEquals($expected, $class->getBaseName());
+    }
+
+    /**
+     * @return array
+     */
+    public function getBaseNameTestCases(): array
+    {
+        return [
+            ['Foo', 'Foo'],
+            ['stdClass', \stdClass::class],
+            ['PHPClass', PHPClass::class],
+        ];
+    }
+
+    /**
+     * @param $expected
+     * @param $fqcn
+     *
+     * @dataProvider getNamespaceTestCases
+     */
+    public function testGetNamespace(string $expected, string $fqcn)
+    {
+        $class = PHPClass::get($fqcn);
+        self::assertEquals($expected, $class->getNamespace());
+    }
+
+    /**
+     * @return array
+     */
+    public function getNamespaceTestCases(): array
+    {
+        return [
+            ['', 'Foo'],
+            ['', \stdClass::class],
+            ['Irstea\\NgModelGeneratorBundle\\Models\\', PHPClass::class],
+        ];
+    }
+
+    /**
+     * @param $expected
+     * @param $fqcn
+     *
+     * @dataProvider getFullNameTestCases
+     */
+    public function testGetFullName(string $fqcn)
+    {
+        $class = PHPClass::get($fqcn);
+        self::assertEquals($fqcn, $class->getFullName());
+    }
+
+    /**
+     * @return array
+     */
+    public function getFullNameTestCases(): array
+    {
+        return [
+            ['Foo'],
+            [\stdClass::class],
+            [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],
+        ];
+    }
+}