Вопрос: Как получить теоретические знания, чтобы иметь возможность описывать то, что я реализую на практике?

Лучший ответ:
Итак, какие конкретно стоит почитать
1. Макконнелл, "Совершенный код". Объемная но не особо сложная книжка, можно прочитать не особо то за большее время чем такую-же книжку из художественной лит-ры.
2. Роберт Мартин, Идеальный программист. Есть ещё "Программист прагматик", вроде тоже о чем то подобном. Книжка небольшая, в принципе можно за пару тройку недель прочитать рассуждения Дяди Боба о работе программиста.
3 Роберт Мартин, Чистый Код. Весьма хорошая книжка, очень широко затрагивает тему написания поддерживаемого кода. Важно - особенно в этой книге, но так же и в любой другой - не зацикливайтесь на догмах аля "3 строчки на функцию", не обожествляйте SOLID, а рассматривайте, какие проблемы решают предложенные решения. Советую в каждом случае рассуждать о том, как описываемые вещи влияют на качество кода и архитектуры программы.
4. Роберт Мартин, Чистая Архитектура - относительно новая книжка о том, что всё новое это хорошо забытое старое. Возможно вещи описываются немножко поверхностно, впрочем, углубляться в любом случае нужно самому. Книжка годная, получше объясняет SOLID, затрагивает другие принципы, затрагивает парадигмы, принципы дизайна, архитектуру, объясняет почему то, что многие горе-разработчики нынче зовут ООП им не является. Думаю эту книжку можно даже перенести на первое место.
Дальше уж по ситуации - паттерны GoF, PoEAA, Рефакторинг Фаулера, Кента Бека про тестирование etc.

подсознательно я продолжаю выбирать именно "правильные" подходы,
Боюсь, что вы просто используете те подходы что знаете, а не выбираете исходя из требований и ситуации.
Хотя бы потому что "правильных" подходов не бывает, есть подходящие в данной ситуации, и плохо подходящие, компромиссные и откровенно вредные.

наследование — это реализовывается само собой.
Вот эта фраза явно даёт понять что у вас есть проблемы в дизайне. Наследование это весьма опасная штука, и делать его просто потому что показалось удобным, не задумываясь об LSP, контрактах и инвариантах.. Кхм.. Плохо.

Упомяну один момент: статейки в интернете и даже(о боги) на всеми нами любимом хабре или тостере, как и любые другие источники информации, книги и доклады любимых нами авторов представляют исключительно субъективное мнение автора, и лишь его понимание описываемой темы, сформировавшееся в силу, обычно, неизвестных нам обстоятельств. Они могут нести за собой скрытую сложность, абсолютно не подходить в ситуациях отличных от ситуации автора, и никогда не стоит принимать из за единственно-верную истину. Скорее, за пищу для размышлений и альтернативные подходы к какому-либо делу.

Худший ответ:
И так, проблема следующая: я реализовываю некоторый функционал, программы и понимаю что делаю и зачем, как это работает, но у меня абсолютно отсутствуют теоретические знания о том, что я сделал. 
Нет, у вас теоретические знания присутствуют, но отсутствует понимание терминологии.
Если у вас уже есть практика, можно почитать теорию, чтобы понять как называется то, что вы делаете.
Но на самом деле, есть подозрение, что вам просто не хватает эрудиции, чтобы внятно излагать свои мысли. Потому что эрудированный человек может объяснить свои действия и терминами и без терминов (но дольше).
Попробуйте предположить, что у вас есть ученик, который не знает простейщих вещей, и вы для него пишете документацию.
Напишите одну документацию по вашей программе (не для юзера, а для программиста), детальную, художественную. Исправьте ее, улучшите ее. Чтобы это было хотя бы страниц 5-10 текста.
После нескольких итераций, когда вы посчитаете, что ее можно дать почитать новичку, возьмите знакомого и почитайте с ним.
После этого еще пару раз исправьте.
На этом у вас должны появиться навыки пояснения того, что вы делаете.