diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 9471daeaee312787d795b137e9e49a467fee00bb..0e36321461b3251fb8a849c61b34bc4702ef7552 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -58,6 +58,7 @@
 #include <cplusplus/TokenCache.h>
 
 #include <cpptools/cppmodelmanagerinterface.h>
+#include <cpptools/cpptoolsconstants.h>
 
 #include <coreplugin/icore.h>
 #include <coreplugin/uniqueidmanager.h>
@@ -603,6 +604,7 @@ CPPEditor::CPPEditor(QWidget *parent)
     , m_inRename(false)
     , m_inRenameChanged(false)
     , m_firstRenameChange(false)
+    , m_objcEnabled(false)
 {
     m_initialized = false;
     qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
@@ -738,6 +740,20 @@ CppTools::CppModelManagerInterface *CPPEditor::modelManager() const
     return m_modelManager;
 }
 
+void CPPEditor::setMimeType(const QString &mt)
+{
+    BaseTextEditor::setMimeType(mt);
+    setObjCEnabled(mt == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE);
+}
+
+void CPPEditor::setObjCEnabled(bool onoff)
+{
+    m_objcEnabled = onoff;
+}
+
+bool CPPEditor::isObjCEnabled() const
+{ return m_objcEnabled; }
+
 void CPPEditor::startRename()
 {
     m_inRenameChanged = false;
@@ -1771,6 +1787,7 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs)
     m_occurrencesUnusedFormat.setToolTip(tr("Unused variable"));
     m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME));
     m_typeFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_TYPE));
+    m_keywordFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_KEYWORD));
 
     // only set the background, we do not want to modify foreground properties set by the syntax highlighter or the link
     m_occurrencesFormat.clearForeground();
@@ -1911,6 +1928,36 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
         }
 
         setExtraSelections(TypeSelection, typeSelections);
+
+        // ### extract common parts from the previous loop and the next one
+        QList<QTextEdit::ExtraSelection> objcKeywords;
+        if (isObjCEnabled()) {
+            foreach (const SemanticInfo::Use &use, semanticInfo.objcKeywords) {
+                QTextCursor cursor(document());
+
+                if (currentLine != use.line) {
+                    int delta = use.line - currentLine;
+
+                    if (delta >= 0) {
+                        while (delta--)
+                            currentBlock = currentBlock.next();
+                    } else {
+                        currentBlock = document()->findBlockByNumber(use.line - 1);
+                    }
+
+                    currentLine = use.line;
+                }
+
+                cursor.setPosition(currentBlock.position() + use.column - 1);
+                cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, use.length);
+
+                QTextEdit::ExtraSelection sel;
+                sel.cursor = cursor;
+                sel.format = m_keywordFormat;
+                objcKeywords.append(sel);
+            }
+        }
+        setExtraSelections(ObjCSelection, objcKeywords);
     }
 
     setExtraSelections(UnusedSymbolSelection, unusedSelections);
@@ -1925,6 +1972,100 @@ void CPPEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
     m_lastSemanticInfo.forced = false; // clear the forced flag
 }
 
+namespace {
+
+class FindObjCKeywords: public ASTVisitor
+{
+public:
+    FindObjCKeywords(TranslationUnit *unit)
+        : ASTVisitor(unit)
+    {}
+
+    QList<SemanticInfo::Use> operator()()
+    {
+        _keywords.clear();
+        accept(translationUnit()->ast());
+        return _keywords;
+    }
+
+    virtual bool visit(ObjCClassDeclarationAST *ast)
+    {
+        addToken(ast->interface_token);
+        addToken(ast->implementation_token);
+        addToken(ast->end_token);
+        return true;
+    }
+
+    virtual bool visit(ObjCClassForwardDeclarationAST *ast)
+    { addToken(ast->class_token); return true; }
+
+    virtual bool visit(ObjCProtocolDeclarationAST *ast)
+    { addToken(ast->protocol_token); addToken(ast->end_token); return true; }
+
+    virtual bool visit(ObjCProtocolForwardDeclarationAST *ast)
+    { addToken(ast->protocol_token); return true; }
+
+    virtual bool visit(ObjCProtocolExpressionAST *ast)
+    { addToken(ast->protocol_token); return true; }
+
+    virtual bool visit(ObjCTypeNameAST *) { return true; }
+
+    virtual bool visit(ObjCEncodeExpressionAST *ast)
+    { addToken(ast->encode_token); return true; }
+
+    virtual bool visit(ObjCSelectorExpressionAST *ast)
+    { addToken(ast->selector_token); return true; }
+
+    virtual bool visit(ObjCVisibilityDeclarationAST *ast)
+    { addToken(ast->visibility_token); return true; }
+
+    virtual bool visit(ObjCPropertyAttributeAST *ast)
+    {
+        const Identifier *attrId = identifier(ast->attribute_identifier_token);
+        if (attrId == control()->objcAssignId()
+                || attrId == control()->objcCopyId()
+                || attrId == control()->objcGetterId()
+                || attrId == control()->objcNonatomicId()
+                || attrId == control()->objcReadonlyId()
+                || attrId == control()->objcReadwriteId()
+                || attrId == control()->objcRetainId()
+                || attrId == control()->objcSetterId())
+            addToken(ast->attribute_identifier_token);
+        return true;
+    }
+
+    virtual bool visit(ObjCPropertyDeclarationAST *ast)
+    { addToken(ast->property_token); return true; }
+
+    virtual bool visit(ObjCSynthesizedPropertiesDeclarationAST *ast)
+    { addToken(ast->synthesized_token); return true; }
+
+    virtual bool visit(ObjCDynamicPropertiesDeclarationAST *ast)
+    { addToken(ast->dynamic_token); return true; }
+
+    virtual bool visit(ObjCFastEnumerationAST *ast)
+    { addToken(ast->for_token); addToken(ast->in_token); return true; }
+
+    virtual bool visit(ObjCSynchronizedStatementAST *ast)
+    { addToken(ast->synchronized_token); return true; }
+
+protected:
+    void addToken(unsigned token)
+    {
+        if (token) {
+            SemanticInfo::Use use;
+            getTokenStartPosition(token, &use.line, &use.column);
+            use.length = tokenAt(token).length();
+            _keywords.append(use);
+        }
+    }
+
+private:
+    QList<SemanticInfo::Use> _keywords;
+};
+
+} // anonymous namespace
+
 SemanticHighlighter::Source CPPEditor::currentSource(bool force)
 {
     int line = 0, column = 0;
@@ -2015,7 +2156,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
     Snapshot snapshot;
     Document::Ptr doc;
     QList<Document::DiagnosticMessage> diagnosticMessages;
-    QList<SemanticInfo::Use> typeUsages;
+    QList<SemanticInfo::Use> typeUsages, objcKeywords;
     LookupContext context;
 
     if (! source.force && revision == source.revision) {
@@ -2024,6 +2165,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
         doc = m_lastSemanticInfo.doc;
         diagnosticMessages = m_lastSemanticInfo.diagnosticMessages;
         typeUsages = m_lastSemanticInfo.typeUsages;
+        objcKeywords = m_lastSemanticInfo.objcKeywords;
         context = m_lastSemanticInfo.context;
         m_mutex.unlock();
     }
@@ -2043,6 +2185,9 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
             typeUsages.clear();
             foreach (const CheckUndefinedSymbols::Use &use, checkUndefinedSymbols.typeUsages()) // ### remove me
                 typeUsages.append(SemanticInfo::Use(use.line, use.column, use.length));
+
+            FindObjCKeywords findObjCKeywords(unit);
+            objcKeywords = findObjCKeywords();
         }
     }
 
@@ -2065,6 +2210,7 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
     semanticInfo.forced = source.force;
     semanticInfo.diagnosticMessages = diagnosticMessages;
     semanticInfo.typeUsages = typeUsages;
+    semanticInfo.objcKeywords = objcKeywords;
     semanticInfo.context = context;
 
     return semanticInfo;
diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h
index 54dce843a5b905bcf97be3f11858f086e763557d..044bc085105325c05f814492ecb2398b3b84839a 100644
--- a/src/plugins/cppeditor/cppeditor.h
+++ b/src/plugins/cppeditor/cppeditor.h
@@ -93,6 +93,7 @@ public:
     CPlusPlus::LookupContext context;
     LocalUseMap localUses; // ### rename
     QList<Use> typeUsages;
+    QList<Use> objcKeywords;
     QList<CPlusPlus::Document::DiagnosticMessage> diagnosticMessages;
 };
 
@@ -203,6 +204,11 @@ public:
 
     CppTools::CppModelManagerInterface *modelManager() const;
 
+    virtual void setMimeType(const QString &mt);
+
+    void setObjCEnabled(bool onoff);
+    bool isObjCEnabled() const;
+
 public Q_SLOTS:
     virtual void setFontSettings(const TextEditor::FontSettings &);
     void setSortedMethodOverview(bool sort);
@@ -297,6 +303,7 @@ private:
     QTextCharFormat m_occurrencesUnusedFormat;
     QTextCharFormat m_occurrenceRenameFormat;
     QTextCharFormat m_typeFormat;
+    QTextCharFormat m_keywordFormat;
 
     QList<QTextEdit::ExtraSelection> m_renameSelections;
     int m_currentRenameSelection;
@@ -307,6 +314,7 @@ private:
     SemanticHighlighter *m_semanticHighlighter;
     SemanticInfo m_lastSemanticInfo;
     QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
+    bool m_objcEnabled;
     bool m_initialized;
 };