diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp
index 98310f9ee8bd737afdca8a6de360cc1420a7d1b6..b21b167655a3ccb96ac8694c2357d619a4922374 100644
--- a/src/libs/3rdparty/cplusplus/Bind.cpp
+++ b/src/libs/3rdparty/cplusplus/Bind.cpp
@@ -2639,10 +2639,14 @@ bool Bind::visit(TemplateIdAST *ast)
     }
 
     const Identifier *id = identifier(ast->identifier_token);
+    const int tokenKindBeforeIdentifier(translationUnit()->tokenKind(ast->identifier_token - 1));
+    const bool isSpecialization = (tokenKindBeforeIdentifier == T_CLASS ||
+                                   tokenKindBeforeIdentifier == T_STRUCT);
     if (templateArguments.empty())
-        _name = control()->templateNameId(id);
+        _name = control()->templateNameId(id, isSpecialization);
     else
-        _name = control()->templateNameId(id, &templateArguments[0], templateArguments.size());
+        _name = control()->templateNameId(id, isSpecialization, &templateArguments[0],
+                templateArguments.size());
 
     ast->name = _name;
     return false;
diff --git a/src/libs/3rdparty/cplusplus/Control.cpp b/src/libs/3rdparty/cplusplus/Control.cpp
index ba709de0527a6aa5b164ff99d3e7e93ed3fd7af5..8f6136534ffdc8220bdd3bfac87ac7dbc577f79a 100644
--- a/src/libs/3rdparty/cplusplus/Control.cpp
+++ b/src/libs/3rdparty/cplusplus/Control.cpp
@@ -131,9 +131,18 @@ template <> struct Compare<TemplateNameId>
         const Identifier *id = name.identifier();
         const Identifier *otherId = otherName.identifier();
 
-        if (id == otherId)
-            return std::lexicographical_compare(name.firstTemplateArgument(), name.lastTemplateArgument(),
-                                                otherName.firstTemplateArgument(), otherName.lastTemplateArgument());
+        if (id == otherId) {
+            // we have to differentiate TemplateNameId with respect to specialization or
+            // instantiation
+            if (name.isSpecialization() == otherName.isSpecialization()) {
+                return std::lexicographical_compare(name.firstTemplateArgument(),
+                                                    name.lastTemplateArgument(),
+                                                    otherName.firstTemplateArgument(),
+                                                    otherName.lastTemplateArgument());
+            } else {
+                return name.isSpecialization();
+            }
+        }
 
         return id < otherId;
     }
@@ -211,9 +220,10 @@ public:
     }
 
     template <typename _Iterator>
-    const TemplateNameId *findOrInsertTemplateNameId(const Identifier *id, _Iterator first, _Iterator last)
+    const TemplateNameId *findOrInsertTemplateNameId(const Identifier *id, bool isSpecialization,
+                                                     _Iterator first, _Iterator last)
     {
-        return templateNameIds.intern(TemplateNameId(id, first, last));
+        return templateNameIds.intern(TemplateNameId(id, isSpecialization, first, last));
     }
 
     const DestructorNameId *findOrInsertDestructorNameId(const Name *name)
@@ -598,10 +608,11 @@ const NumericLiteral *Control::numericLiteral(const char *chars)
 }
 
 const TemplateNameId *Control::templateNameId(const Identifier *id,
+                                              bool isSpecialization,
                                               const FullySpecifiedType *const args,
                                               unsigned argv)
 {
-    return d->findOrInsertTemplateNameId(id, args, args + argv);
+    return d->findOrInsertTemplateNameId(id, isSpecialization, args, args + argv);
 }
 
 const DestructorNameId *Control::destructorNameId(const Name *name)
diff --git a/src/libs/3rdparty/cplusplus/Control.h b/src/libs/3rdparty/cplusplus/Control.h
index 4132d5f3cfaa695ad2e67b70d341b66e55a37170..cef4df40f75ba0d3cd459845c17d9c2bad91beb8 100644
--- a/src/libs/3rdparty/cplusplus/Control.h
+++ b/src/libs/3rdparty/cplusplus/Control.h
@@ -51,6 +51,7 @@ public:
 
     /// Returns the canonical template name id.
     const TemplateNameId *templateNameId(const Identifier *id,
+                                         bool isSpecialization,
                                          const FullySpecifiedType *const args = 0,
                                          unsigned argc = 0);
 
diff --git a/src/libs/3rdparty/cplusplus/Names.cpp b/src/libs/3rdparty/cplusplus/Names.cpp
index 9024b65a914a4f517cb618ff6678f6304045373e..4c5cb7db7949ba18551aa69f233db9a10c65c289 100644
--- a/src/libs/3rdparty/cplusplus/Names.cpp
+++ b/src/libs/3rdparty/cplusplus/Names.cpp
@@ -128,6 +128,27 @@ bool TemplateNameId::isEqualTo(const Name *other) const
     return true;
 }
 
+bool TemplateNameId::Compare::operator()(const TemplateNameId *name,
+                                         const TemplateNameId *other) const
+{
+    const Identifier *id = name->identifier();
+    const Identifier *otherId = other->identifier();
+
+    if (id == otherId) {
+        // we have to differentiate TemplateNameId with respect to specialization or instantiation
+        if (name->isSpecialization() == other->isSpecialization()) {
+            return std::lexicographical_compare(name->firstTemplateArgument(),
+                                                name->lastTemplateArgument(),
+                                                other->firstTemplateArgument(),
+                                                other->lastTemplateArgument());
+        } else {
+            return name->isSpecialization();
+        }
+    }
+
+    return id < otherId;
+}
+
 OperatorNameId::OperatorNameId(Kind kind)
     : _kind(kind)
 { }
diff --git a/src/libs/3rdparty/cplusplus/Names.h b/src/libs/3rdparty/cplusplus/Names.h
index 70c782591f5264939af57a7e9bc5328598a9e03d..e600ec1dafee8abd8d1190b999a55167469c3bc8 100644
--- a/src/libs/3rdparty/cplusplus/Names.h
+++ b/src/libs/3rdparty/cplusplus/Names.h
@@ -80,8 +80,11 @@ class CPLUSPLUS_EXPORT TemplateNameId: public Name
 {
 public:
     template <typename _Iterator>
-    TemplateNameId(const Identifier *identifier, _Iterator first, _Iterator last)
-        : _identifier(identifier), _templateArguments(first, last) {}
+    TemplateNameId(const Identifier *identifier, bool isSpecialization, _Iterator first,
+                   _Iterator last)
+        : _identifier(identifier)
+        , _templateArguments(first, last)
+        , _isSpecialization(isSpecialization) {}
 
     virtual ~TemplateNameId();
 
@@ -100,6 +103,15 @@ public:
 
     TemplateArgumentIterator firstTemplateArgument() const { return _templateArguments.begin(); }
     TemplateArgumentIterator lastTemplateArgument() const { return _templateArguments.end(); }
+    bool isSpecialization() const { return _isSpecialization; }
+    // this is temporary solution needed in ClassOrNamespace::nestedType
+    // when we try to find correct specialization for instantiation
+    void setIsSpecialization(bool isSpecialization) { _isSpecialization = isSpecialization; }
+
+    // Comparator needed to distinguish between two different TemplateNameId(e.g.:used in std::map)
+    struct Compare: std::binary_function<const TemplateNameId *, const TemplateNameId *, bool> {
+        bool operator()(const TemplateNameId *name, const TemplateNameId *other) const;
+    };
 
 protected:
     virtual void accept0(NameVisitor *visitor) const;
@@ -107,6 +119,8 @@ protected:
 private:
     const Identifier *_identifier;
     std::vector<FullySpecifiedType> _templateArguments;
+    // now TemplateNameId can be a specialization or an instantiation
+    bool _isSpecialization;
 };
 
 class CPLUSPLUS_EXPORT OperatorNameId: public Name
diff --git a/src/libs/3rdparty/cplusplus/Templates.cpp b/src/libs/3rdparty/cplusplus/Templates.cpp
index fd1ee873d9ea33f793c47720709603a0b166956d..c81ed51b09c483f750dbc56f75044cb0ff435995 100644
--- a/src/libs/3rdparty/cplusplus/Templates.cpp
+++ b/src/libs/3rdparty/cplusplus/Templates.cpp
@@ -414,9 +414,10 @@ void CloneName::visit(const TemplateNameId *name)
     for (unsigned i = 0; i < args.size(); ++i)
         args[i] = _clone->type(name->templateArgumentAt(i), _subst);
     if (args.empty())
-        _name = _control->templateNameId(_clone->identifier(name->identifier()));
+        _name = _control->templateNameId(_clone->identifier(name->identifier()), name->isSpecialization());
     else
-        _name = _control->templateNameId(_clone->identifier(name->identifier()), &args[0], args.size());
+        _name = _control->templateNameId(_clone->identifier(name->identifier()), name->isSpecialization(),
+                                         &args[0], args.size());
 }
 
 void CloneName::visit(const DestructorNameId *name)
@@ -528,7 +529,8 @@ FullySpecifiedType Subst::apply(const Name *name) const
             const NamedType *name = apply(q->base())->asNamedType();
             const NamedType *unqualified = apply(q->name())->asNamedType();
             if (name && name->name()->identifier() != 0 && unqualified)
-                return control()->namedType(control()->qualifiedNameId(name->name()->identifier(), unqualified->name()));
+                return control()->namedType(control()->qualifiedNameId(name->name()->identifier(),
+                                                                       unqualified->name()));
         }
 
     }
diff --git a/src/libs/cplusplus/CppRewriter.cpp b/src/libs/cplusplus/CppRewriter.cpp
index 2dee6ddc9434a35ebe0603649f2639b8c7c41903..15d3b9d156fe723055281ca14bfecf3c347ff266 100644
--- a/src/libs/cplusplus/CppRewriter.cpp
+++ b/src/libs/cplusplus/CppRewriter.cpp
@@ -263,7 +263,8 @@ public:
             QVarLengthArray<FullySpecifiedType, 8> args(name->templateArgumentCount());
             for (unsigned i = 0; i < name->templateArgumentCount(); ++i)
                 args[i] = rewrite->rewriteType(name->templateArgumentAt(i));
-            temps.append(control()->templateNameId(identifier(name->identifier()), args.data(), args.size()));
+            temps.append(control()->templateNameId(identifier(name->identifier()), name->isSpecialization(),
+                                                   args.data(), args.size()));
         }
 
         virtual void visit(const DestructorNameId *name)
diff --git a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp
index eb27a6bf555cf5a52a2c3fff5a61501773bd761d..83a833cc38932300ef0a6c113ade03dce39fe323 100644
--- a/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp
+++ b/src/libs/cplusplus/DeprecatedGenTemplateInstance.cpp
@@ -253,6 +253,7 @@ private:
             }
 
             const TemplateNameId *templId = control()->templateNameId(name->identifier(),
+                                                                      name->isSpecialization(),
                                                                       arguments.data(),
                                                                       arguments.size());
             _type = control()->namedType(templId);
@@ -269,13 +270,15 @@ private:
 
             } else if (const TemplateNameId *templId = name->asTemplateNameId()) {
                 QVarLengthArray<FullySpecifiedType, 8> arguments(templId->templateArgumentCount());
-                for (unsigned templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount(); ++templateArgIndex) {
+                for (unsigned templateArgIndex = 0; templateArgIndex < templId->templateArgumentCount();
+                     ++templateArgIndex) {
                     FullySpecifiedType argTy = templId->templateArgumentAt(templateArgIndex);
                     arguments[templateArgIndex] = q->apply(argTy);
                 }
                 const Identifier *id = control()->identifier(templId->identifier()->chars(),
                                                                          templId->identifier()->size());
-                return control()->templateNameId(id, arguments.data(), arguments.size());
+                return control()->templateNameId(id, templId->isSpecialization(), arguments.data(),
+                                                 arguments.size());
 
             } else if (const QualifiedNameId *qq = name->asQualifiedNameId()) {
                 const Name *base = instantiate(qq->base());
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index b73c22b6571c6721feb46d459450d5ded03fc230..32e2fef6ddc8968913069584ec062fe68a2b636c 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -716,6 +716,42 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
 
     ClassOrNamespace *reference = it->second;
 
+    const TemplateNameId *templId = name->asTemplateNameId();
+    if (templId) {
+        // if it is a TemplateNameId it could be a specialization(full or partial) or
+        // instantiation of one of the specialization(reference->_specialization) or
+        // base class(reference)
+        if (templId->isSpecialization()) {
+            // if it is a specialization we try to find or create new one and
+            // add to base class(reference)
+            TemplateNameIdTable::const_iterator cit = reference->_specializations.find(templId);
+            if (cit != reference->_specializations.end()) {
+                return cit->second;
+            } else {
+                ClassOrNamespace *newSpecialization = _factory->allocClassOrNamespace(reference);
+#ifdef DEBUG_LOOKUP
+                newSpecialization->_name = templId;
+#endif // DEBUG_LOOKUP
+                reference->_specializations[templId] = newSpecialization;
+                return newSpecialization;
+            }
+        } else {
+            TemplateNameId *nonConstTemplId = const_cast<TemplateNameId *>(templId);
+            // make this instantiation looks like specialization which help to find
+            // full specialization for this instantiation
+            nonConstTemplId->setIsSpecialization(true);
+            TemplateNameIdTable::const_iterator cit = reference->_specializations.find(templId);
+            if (cit != reference->_specializations.end()) {
+                // we found full specialization
+                reference = cit->second;
+            } else {
+                // TODO: find the best specialization(probably partial) for this instantiation
+            }
+            // let's instantiation be instantiation
+            nonConstTemplId->setIsSpecialization(false);
+        }
+    }
+
     // The reference binding might still be missing some of its base classes in the case they
     // are templates. We need to collect them now. First, we track the bases which are already
     // part of the binding so we can identify the missings ones later.
@@ -737,7 +773,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
     if (!referenceClass)
         return reference;
 
-    const TemplateNameId *templId = name->asTemplateNameId();
     if ((! templId && _alreadyConsideredClasses.contains(referenceClass)) ||
             (templId &&
             _alreadyConsideredTemplates.contains(templId))) {
@@ -752,9 +787,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
     // If we are dealling with a template type, more work is required, since we need to
     // construct all instantiation data.
     if (templId) {
-        if (_instantiations.contains(templId))
-            return _instantiations[templId];
-
         _alreadyConsideredTemplates.insert(templId);
         ClassOrNamespace *instantiation = _factory->allocClassOrNamespace(reference);
 #ifdef DEBUG_LOOKUP
@@ -863,7 +895,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
         }
 
         _alreadyConsideredTemplates.clear(templId);
-        _instantiations[templId] = instantiation;
         return instantiation;
     }
 
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
index 8144cbfa84d615785a16a8c8b8e684c9d46b8964..d5f6a9acc3e2c013b6dbd6cc7fd4f3eccc092479 100644
--- a/src/libs/cplusplus/LookupContext.h
+++ b/src/libs/cplusplus/LookupContext.h
@@ -101,6 +101,7 @@ private:
 
 private:
     typedef std::map<const Name *, ClassOrNamespace *, Name::Compare> Table;
+    typedef std::map<const TemplateNameId *, ClassOrNamespace *, TemplateNameId::Compare> TemplateNameIdTable;
 
     CreateBindings *_factory;
     ClassOrNamespace *_parent;
@@ -110,7 +111,7 @@ private:
     QList<Enum *> _enums;
     QList<Symbol *> _todo;
     QSharedPointer<Control> _control;
-    QMap<const Name *, ClassOrNamespace *> _instantiations;
+    TemplateNameIdTable _specializations;
 
     // it's an instantiation.
     const TemplateNameId *_templateId;
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index 80471cd8dfb89429e139900c837db8bac6f3b298..63325d521ff1dc4d6b61f2b6a87b4ce89fe93f91 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -564,6 +564,42 @@ void CppToolsPlugin::test_completion_type_of_pointer_is_typedef()
     QVERIFY(completions.contains(QLatin1String("foo")));
 }
 
+void CppToolsPlugin::test_completion_instantiate_full_specialization()
+{
+    TestData data;
+    data.srcText = "\n"
+            "template<typename T>\n"
+            "struct Template\n"
+            "{\n"
+            "   int templateT_i;\n"
+            "};\n"
+            "\n"
+            "template<>\n"
+            "struct Template<char>\n"
+            "{\n"
+            "    int templateChar_i;\n"
+            "};\n"
+            "\n"
+            "Template<char> templateChar;\n"
+            "@\n"
+            ;
+
+    setup(&data);
+
+    Utils::ChangeSet change;
+    QString txt = QLatin1String("templateChar.");
+    change.insert(data.pos, txt);
+    QTextCursor cursor(data.doc);
+    change.apply(&cursor);
+    data.pos += txt.length();
+
+    QStringList completions = getCompletions(data);
+
+    QCOMPARE(completions.size(), 2);
+    QVERIFY(completions.contains(QLatin1String("Template")));
+    QVERIFY(completions.contains(QLatin1String("templateChar_i")));
+}
+
 void CppToolsPlugin::test_completion()
 {
     QFETCH(QByteArray, code);
diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h
index 012d03112cf7f8e49ae4c20efea0f8797a7ede8a..ba6c47a548da37158f7a51e484ab61a9c8611529 100644
--- a/src/plugins/cpptools/cpptoolsplugin.h
+++ b/src/plugins/cpptools/cpptoolsplugin.h
@@ -100,6 +100,7 @@ private slots:
     void test_completion_template_6();
     void test_completion_template_7();
     void test_completion_type_of_pointer_is_typedef();
+    void test_completion_instantiate_full_specialization();
     void test_completion_template_as_base();
     void test_completion_template_as_base_data();
     void test_completion_use_global_identifier_as_base_class();
diff --git a/tests/auto/cplusplus/semantic/tst_semantic.cpp b/tests/auto/cplusplus/semantic/tst_semantic.cpp
index 9644621cf7361e7670f8b0c526978b837aaa944e..cf789c554226439a385db03b50fcb372e66aa3f7 100644
--- a/tests/auto/cplusplus/semantic/tst_semantic.cpp
+++ b/tests/auto/cplusplus/semantic/tst_semantic.cpp
@@ -481,7 +481,7 @@ void tst_Semantic::template_instance_1()
     QVERIFY(decl);
 
     FullySpecifiedType templArgs[] = { control->integerType(IntegerType::Int) };
-    const Name *templId = control->templateNameId(control->identifier("QList"), templArgs, 1);
+    const Name *templId = control->templateNameId(control->identifier("QList"), false, templArgs, 1);
 
     FullySpecifiedType genTy = DeprecatedGenTemplateInstance::instantiate(templId, decl, control);